Merge branch 'devel/master' into tizen
authorTaehyub Kim <taehyub.kim@samsung.com>
Tue, 8 Jun 2021 10:38:49 +0000 (19:38 +0900)
committerTaehyub Kim <taehyub.kim@samsung.com>
Tue, 8 Jun 2021 10:38:49 +0000 (19:38 +0900)
Change-Id: I070b4e6e450ecdf2d052b0fb834eecd1962f2119

189 files changed:
automated-tests/resources/papermill_E_diffuse-64.ktx [new file with mode: 0644]
automated-tests/resources/shape.riv [new file with mode: 0644]
automated-tests/src/dali-scene-loader-internal/CMakeLists.txt
automated-tests/src/dali-scene-loader/CMakeLists.txt
automated-tests/src/dali-scene-loader/utc-Dali-KtxLoader.cpp
automated-tests/src/dali-scene-loader/utc-Dali-MeshDefinition.cpp [new file with mode: 0644]
automated-tests/src/dali-shader-generator/CMakeLists.txt
automated-tests/src/dali-shader-generator/tct-dali-shader-generator-core.cpp
automated-tests/src/dali-shader-generator/utc-Dali-ShaderGenerator.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/CMakeLists.txt
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.h
automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Controls-BridgeUp.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Controls.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-BidirectionalSupport.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-LogicalModel.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Cursor.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Hyphen-Wrapping.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Layout.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Markup.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Shaping.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-TextEditor-internal.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-TextLabel-internal.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-VisualModel.cpp
automated-tests/src/dali-toolkit-styling/CMakeLists.txt
automated-tests/src/dali-toolkit-third-party/CMakeLists.txt
automated-tests/src/dali-toolkit/CMakeLists.txt
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-actor-utils.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-actor-utils.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-application.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-application.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-buffer.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-buffer.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-command-buffer.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-command-buffer.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-framebuffer.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-framebuffer.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-pipeline.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-render-pass.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-render-target.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-impl.cpp [moved from automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-sync-abstraction.cpp with 66% similarity]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-impl.h [moved from automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-sync-abstraction.h with 64% similarity]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-object.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-object.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-texture.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-texture.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-scene-holder-impl.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-vector-animation-renderer.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-vector-animation-renderer.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-web-engine.cpp
automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-AnimatedVectorImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-Control.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-KeyboardFocusManager.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
automated-tests/src/dali-toolkit/utc-Dali-VideoView.cpp
automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp
automated-tests/src/dali-toolkit/utc-Dali-WebView.cpp
build/tizen/CMakeLists.txt
build/tizen/dali-scene-loader/CMakeLists.txt
dali-scene-loader/public-api/ktx-loader.cpp
dali-scene-loader/public-api/mesh-definition.cpp
dali-toolkit/devel-api/controls/accessible-impl.cpp
dali-toolkit/devel-api/controls/control-devel.h
dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h
dali-toolkit/devel-api/controls/web-view/web-view.cpp
dali-toolkit/devel-api/controls/web-view/web-view.h
dali-toolkit/devel-api/file.list
dali-toolkit/devel-api/focus-manager/focus-finder.cpp [new file with mode: 0644]
dali-toolkit/devel-api/focus-manager/focus-finder.h [new file with mode: 0644]
dali-toolkit/devel-api/layouting/flex-node.h
dali-toolkit/devel-api/text/text-enumerations-devel.h
dali-toolkit/devel-api/text/text-utils-devel.cpp
dali-toolkit/devel-api/utility/npatch-utilities.cpp
dali-toolkit/devel-api/visuals/color-visual-properties-devel.h
dali-toolkit/devel-api/visuals/visual-properties-devel.h
dali-toolkit/internal/controls/control/control-data-impl.cpp
dali-toolkit/internal/controls/control/control-data-impl.h
dali-toolkit/internal/controls/flex-container/flex-container-impl.cpp
dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp
dali-toolkit/internal/controls/text-controls/text-editor-impl.h
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.h
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/controls/video-view/video-view-impl.cpp
dali-toolkit/internal/controls/web-view/web-view-impl.cpp [changed mode: 0644->0755]
dali-toolkit/internal/controls/web-view/web-view-impl.h
dali-toolkit/internal/file.list
dali-toolkit/internal/focus-manager/focus-finder-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/focus-manager/focus-finder-impl.h [new file with mode: 0644]
dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp
dali-toolkit/internal/graphics/shaders/color-visual-blur-edge-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/color-visual-blur-edge-shader.vert [deleted file]
dali-toolkit/internal/graphics/shaders/color-visual-rounded-corner-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/color-visual-rounded-corner-shader.vert [deleted file]
dali-toolkit/internal/graphics/shaders/color-visual-shader.frag
dali-toolkit/internal/graphics/shaders/color-visual-shader.vert
dali-toolkit/internal/graphics/shaders/glyphy-common-glsl-shader.def [new file with mode: 0644]
dali-toolkit/internal/graphics/shaders/glyphy-sdf-glsl-shader.def [new file with mode: 0644]
dali-toolkit/internal/graphics/shaders/glyphy-shader-extention-prefix.def [new file with mode: 0644]
dali-toolkit/internal/graphics/shaders/glyphy-shader-fragment-prefix.frag [new file with mode: 0644]
dali-toolkit/internal/graphics/shaders/glyphy-shader-main.frag [new file with mode: 0644]
dali-toolkit/internal/graphics/shaders/glyphy-shader-main.vert [new file with mode: 0644]
dali-toolkit/internal/graphics/shaders/gradient-visual-bounding-box-rounded-corner-shader.vert [deleted file]
dali-toolkit/internal/graphics/shaders/gradient-visual-bounding-box-shader.vert [deleted file]
dali-toolkit/internal/graphics/shaders/gradient-visual-linear-rounded-corner-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/gradient-visual-linear-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/gradient-visual-radial-rounded-corner-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/gradient-visual-radial-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/gradient-visual-shader.frag [new file with mode: 0644]
dali-toolkit/internal/graphics/shaders/gradient-visual-shader.vert [new file with mode: 0644]
dali-toolkit/internal/graphics/shaders/gradient-visual-user-space-rounded-corner-shader.vert [deleted file]
dali-toolkit/internal/graphics/shaders/gradient-visual-user-space-shader.vert [deleted file]
dali-toolkit/internal/graphics/shaders/image-visual-atlas-clamp-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/image-visual-atlas-various-wrap-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/image-visual-no-atlas-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/image-visual-rounded-corner-shader.frag [deleted file]
dali-toolkit/internal/graphics/shaders/image-visual-rounded-corner-shader.vert [deleted file]
dali-toolkit/internal/graphics/shaders/image-visual-shader.frag [new file with mode: 0644]
dali-toolkit/internal/graphics/shaders/image-visual-shader.vert
dali-toolkit/internal/text/hyphenator.cpp [new file with mode: 0644]
dali-toolkit/internal/text/hyphenator.h [new file with mode: 0644]
dali-toolkit/internal/text/layouts/layout-engine.cpp
dali-toolkit/internal/text/logical-model-impl.cpp
dali-toolkit/internal/text/logical-model-impl.h
dali-toolkit/internal/text/markup-processor.cpp
dali-toolkit/internal/text/markup-processor.h
dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp
dali-toolkit/internal/text/rendering/text-typesetter.cpp
dali-toolkit/internal/text/rendering/text-typesetter.h
dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-common-glsl.h [deleted file]
dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-sdf-glsl.h [deleted file]
dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.cpp
dali-toolkit/internal/text/rendering/view-model.cpp
dali-toolkit/internal/text/rendering/view-model.h
dali-toolkit/internal/text/text-controller-impl-event-handler.cpp
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/internal/text/text-controller-impl.h
dali-toolkit/internal/text/text-controller-relayouter.cpp
dali-toolkit/internal/text/text-controller-text-updater.cpp
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-model-interface.h
dali-toolkit/internal/text/text-model.cpp
dali-toolkit/internal/text/text-model.h
dali-toolkit/internal/text/text-view-interface.h
dali-toolkit/internal/text/text-view.cpp
dali-toolkit/internal/text/text-view.h
dali-toolkit/internal/text/underlined-character-run.h [new file with mode: 0644]
dali-toolkit/internal/text/visual-model-impl.cpp
dali-toolkit/internal/text/visual-model-impl.h
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp
dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h
dali-toolkit/internal/visuals/color/color-visual.cpp
dali-toolkit/internal/visuals/color/color-visual.h
dali-toolkit/internal/visuals/gradient/gradient-visual.cpp
dali-toolkit/internal/visuals/image-visual-shader-factory.cpp
dali-toolkit/internal/visuals/image-visual-shader-factory.h
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/npatch/npatch-visual.cpp
dali-toolkit/internal/visuals/svg/svg-visual.cpp
dali-toolkit/internal/visuals/text/text-visual.cpp
dali-toolkit/internal/visuals/texture-manager-impl.cpp
dali-toolkit/internal/visuals/visual-base-data-impl.cpp
dali-toolkit/internal/visuals/visual-base-data-impl.h
dali-toolkit/internal/visuals/visual-base-impl.cpp
dali-toolkit/internal/visuals/visual-base-impl.h
dali-toolkit/internal/visuals/visual-factory-cache.h
dali-toolkit/internal/visuals/visual-factory-impl.cpp
dali-toolkit/internal/visuals/visual-string-constants.cpp
dali-toolkit/internal/visuals/visual-string-constants.h
dali-toolkit/internal/visuals/visual-url.cpp
dali-toolkit/internal/visuals/visual-url.h
dali-toolkit/public-api/controls/control-impl.cpp
dali-toolkit/public-api/controls/flex-container/flex-container.h
dali-toolkit/public-api/dali-toolkit-version.cpp
docs/content/programming-guide/flex-container.md
packaging/dali-toolkit.spec

diff --git a/automated-tests/resources/papermill_E_diffuse-64.ktx b/automated-tests/resources/papermill_E_diffuse-64.ktx
new file mode 100644 (file)
index 0000000..c000b61
Binary files /dev/null and b/automated-tests/resources/papermill_E_diffuse-64.ktx differ
diff --git a/automated-tests/resources/shape.riv b/automated-tests/resources/shape.riv
new file mode 100644 (file)
index 0000000..2450a94
Binary files /dev/null and b/automated-tests/resources/shape.riv differ
index 16f96f0..0270d3d 100755 (executable)
@@ -42,10 +42,12 @@ SET(TEST_HARNESS_SOURCES
   ${TEST_HARNESS_DIR}/test-harness.cpp
   ${TEST_HARNESS_DIR}/test-gesture-generator.cpp
   ${TEST_HARNESS_DIR}/test-gl-abstraction.cpp
-  ${TEST_HARNESS_DIR}/test-gl-sync-abstraction.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-sync-impl.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-sync-object.cpp
   ${TEST_HARNESS_DIR}/test-graphics-buffer.cpp
   ${TEST_HARNESS_DIR}/test-graphics-command-buffer.cpp
   ${TEST_HARNESS_DIR}/test-graphics-controller.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-framebuffer.cpp
   ${TEST_HARNESS_DIR}/test-graphics-texture.cpp
   ${TEST_HARNESS_DIR}/test-graphics-sampler.cpp
   ${TEST_HARNESS_DIR}/test-graphics-pipeline.cpp
index f0d84fb..60c1b22 100755 (executable)
@@ -16,6 +16,7 @@ SET(TC_SOURCES
   utc-Dali-Gltf2Loader.cpp
   utc-Dali-KtxLoader.cpp
   utc-Dali-MatrixStack.cpp
+  utc-Dali-MeshDefinition.cpp
   utc-Dali-NodeDefinition.cpp
   utc-Dali-RendererState.cpp
   utc-Dali-ResourceBundle.cpp
@@ -56,9 +57,11 @@ SET(TEST_HARNESS_SOURCES
   ${TEST_HARNESS_DIR}/test-harness.cpp
   ${TEST_HARNESS_DIR}/test-gesture-generator.cpp
   ${TEST_HARNESS_DIR}/test-gl-abstraction.cpp
-  ${TEST_HARNESS_DIR}/test-gl-sync-abstraction.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-sync-impl.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-sync-object.cpp
   ${TEST_HARNESS_DIR}/test-graphics-buffer.cpp
   ${TEST_HARNESS_DIR}/test-graphics-command-buffer.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-framebuffer.cpp
   ${TEST_HARNESS_DIR}/test-graphics-controller.cpp
   ${TEST_HARNESS_DIR}/test-graphics-texture.cpp
   ${TEST_HARNESS_DIR}/test-graphics-sampler.cpp
index 15d6b58..783745d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -146,3 +146,20 @@ int UtcDaliKtxLoaderCubeDataCreateTexture2(void)
 
   END_TEST;
 }
+
+int UtcDaliKtxLoaderCubeDataCreateTexture3(void)
+{
+  CubeData cubeData;
+  auto path = TEST_RESOURCE_DIR "/papermill_E_diffuse-64.ktx";
+  DALI_TEST_CHECK(LoadCubeMapData(path, cubeData));
+
+  TestApplication app;
+  auto texture = cubeData.CreateTexture();
+
+  DALI_TEST_CHECK(texture);
+  DALI_TEST_EQUAL(64u, texture.GetWidth());
+  DALI_TEST_EQUAL(64u, texture.GetHeight());
+
+  END_TEST;
+
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-MeshDefinition.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-MeshDefinition.cpp
new file mode 100644 (file)
index 0000000..37c170b
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <vector>
+
+#include "dali-scene-loader/public-api/mesh-definition.h"
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+int UtcDaliMeshDefinitionBlobApplyMinMaxBothMinMaxApplied(void)
+{
+  using Container = std::vector<float>;
+
+  Container buffer = { 4.0f, 6.0f, 8.0f, 10.0f, 12.0f };
+  Container minValues = { 5.0f };
+  Container maxValues = { 10.0f };
+  Container result = {5.0f, 6.0f, 8.0f, 10.0f, 10.0f};
+
+  MeshDefinition::Blob::ApplyMinMax(minValues, maxValues, 5, buffer.data());
+
+  for( auto i = 0u; i < result.size(); ++i)
+  {
+    DALI_TEST_EQUALS(buffer[i], result[i], TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliMeshDefinitionBlobApplyMinMaxOnlyMin(void)
+{
+  using Container = std::vector<float>;
+
+  Container buffer = { 4.0f, 6.0f, 8.0f, 10.0f, 12.0f };
+  Container minValues = { 5.0f };
+  Container maxValues = {};
+  Container result = {5.0f, 6.0f, 8.0f, 10.0f, 12.0f};
+
+  MeshDefinition::Blob::ApplyMinMax(minValues, maxValues, 5, buffer.data());
+
+  for( auto i = 0u; i < result.size(); ++i)
+  {
+    DALI_TEST_EQUALS(buffer[i], result[i], TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliMeshDefinitionBlobApplyMinMaxOnlyMax(void)
+{
+  using Container = std::vector<float>;
+
+  Container buffer = { 4.0f, 6.0f, 8.0f, 10.0f, 12.0f };
+  Container minValues = { };
+  Container maxValues = { 10.0f };
+  Container result = {4.0f, 6.0f, 8.0f, 10.0f, 10.0f};
+
+  MeshDefinition::Blob::ApplyMinMax(minValues, maxValues, 5, buffer.data());
+
+  for( auto i = 0u; i < result.size(); ++i)
+  {
+    DALI_TEST_EQUALS(buffer[i], result[i], TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliMeshDefinitionBlobApplyMinMaxBothEmpty(void)
+{
+  using Container = std::vector<float>;
+
+  Container buffer = { 4.0f, 6.0f, 8.0f, 10.0f, 12.0f };
+  Container minValues;
+  Container maxValues;
+  Container result = {4.0f, 6.0f, 8.0f, 10.0f, 12.0f};
+
+  MeshDefinition::Blob::ApplyMinMax(minValues, maxValues, 5, buffer.data());
+
+  for( auto i = 0u; i < result.size(); ++i)
+  {
+    DALI_TEST_EQUALS(buffer[i], result[i], TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
index 7057a36..517b7d3 100644 (file)
 SET(PKG_NAME "dali-shader-generator")
 
 SET(EXEC_NAME "tct-${PKG_NAME}-core")
+SET(EXEC_NAME "tct-${PKG_NAME}-core")
+
+SET(CAPI_LIB "dali-shader-generator")
 
-PKG_CHECK_MODULES(${EXEC_NAME} REQUIRED
+PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
+  dali2-core
+  dali2-adaptor
   dali2-toolkit
 )
 
-ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp)
+SET(TC_SOURCES
+  utc-Dali-ShaderGenerator.cpp
+)
+
+# List of test harness files (Won't get parsed for test cases)
+SET(TEST_HARNESS_DIR "../dali-toolkit/dali-toolkit-test-utils")
+
+SET(TEST_HARNESS_SOURCES
+  ${TEST_HARNESS_DIR}/toolkit-adaptor.cpp
+  ${TEST_HARNESS_DIR}/toolkit-application.cpp
+  ${TEST_HARNESS_DIR}/toolkit-event-thread-callback.cpp
+  ${TEST_HARNESS_DIR}/toolkit-environment-variable.cpp
+  ${TEST_HARNESS_DIR}/toolkit-input-method-context.cpp
+  ${TEST_HARNESS_DIR}/toolkit-input-method-options.cpp
+  ${TEST_HARNESS_DIR}/toolkit-lifecycle-controller.cpp
+  ${TEST_HARNESS_DIR}/toolkit-orientation.cpp
+  ${TEST_HARNESS_DIR}/toolkit-style-monitor.cpp
+  ${TEST_HARNESS_DIR}/toolkit-test-application.cpp
+  ${TEST_HARNESS_DIR}/toolkit-timer.cpp
+  ${TEST_HARNESS_DIR}/toolkit-trigger-event-factory.cpp
+  ${TEST_HARNESS_DIR}/toolkit-window.cpp
+  ${TEST_HARNESS_DIR}/toolkit-scene-holder.cpp
+  ${TEST_HARNESS_DIR}/dali-test-suite-utils.cpp
+  ${TEST_HARNESS_DIR}/dali-toolkit-test-suite-utils.cpp
+  ${TEST_HARNESS_DIR}/dummy-control.cpp
+  ${TEST_HARNESS_DIR}/mesh-builder.cpp
+  ${TEST_HARNESS_DIR}/test-actor-utils.cpp
+  ${TEST_HARNESS_DIR}/test-animation-data.cpp
+  ${TEST_HARNESS_DIR}/test-application.cpp
+  ${TEST_HARNESS_DIR}/test-button.cpp
+  ${TEST_HARNESS_DIR}/test-harness.cpp
+  ${TEST_HARNESS_DIR}/test-gesture-generator.cpp
+  ${TEST_HARNESS_DIR}/test-gl-abstraction.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-sync-impl.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-sync-object.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-buffer.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-command-buffer.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-controller.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-framebuffer.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-texture.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-sampler.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-program.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-pipeline.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-shader.cpp
+  ${TEST_HARNESS_DIR}/test-graphics-reflection.cpp
+  ${TEST_HARNESS_DIR}/test-platform-abstraction.cpp
+  ${TEST_HARNESS_DIR}/test-render-controller.cpp
+  ${TEST_HARNESS_DIR}/test-trace-call-stack.cpp
+)
+
+ADD_DEFINITIONS(-DTEST_RESOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../resources\" )
+
+FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
+    SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}")
+ENDFOREACH(directory ${CAPI_LIB_LIBRARY_DIRS})
+
+INCLUDE_DIRECTORIES(
+  ../../../
+  ${${CAPI_LIB}_INCLUDE_DIRS}
+  ../dali-toolkit/dali-toolkit-test-utils
+)
+
+ADD_COMPILE_OPTIONS( -O0 -ggdb --coverage -Wall -Werror -DDEBUG_ENABLED)
+ADD_COMPILE_OPTIONS( ${${CAPI_LIB}_CFLAGS_OTHER} )
+
+ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.h ${EXEC_NAME}.cpp ${TC_SOURCES} ${TEST_HARNESS_SOURCES})
+
+TARGET_LINK_LIBRARIES(${EXEC_NAME}
+  ${${CAPI_LIB}_LIBRARIES}
+  -lpthread --coverage
+)
+
+ADD_CUSTOM_COMMAND(
+  COMMAND ${SCRIPT_DIR}/tcheadgen.sh ${EXEC_NAME}.h ${TC_SOURCES}
+  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+  OUTPUT ${EXEC_NAME}.h
+  COMMENT "Generating test tables"
+)
 
 INSTALL(PROGRAMS ${EXEC_NAME}
-    DESTINATION ${BIN_DIR}/${EXEC_NAME}
+  DESTINATION ${BIN_DIR}/${EXEC_NAME}
 )
 
 SET(SHADER_GENERATOR dali-shader-generator)
 SET(GENERATED_FOLDER ${CMAKE_CURRENT_BINARY_DIR}/shader/generated)
 SET(SHADER_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/shader)
 
+# All the shader generator execution tests are below
+
 ADD_CUSTOM_TARGET(test_help ALL COMMAND ${SHADER_GENERATOR} -h | grep "DALi Shader Generator" > /dev/null 2>&1 && echo "test_help Succeeded" VERBATIM)
 ADD_CUSTOM_TARGET(test_no_params ALL COMMAND ${SHADER_GENERATOR} > /dev/null 2>&1 || echo "test_no_params Succeeded" VERBATIM)
 ADD_CUSTOM_TARGET(test_version ALL COMMAND ${SHADER_GENERATOR} -v | wc -l | grep 1 > /dev/null 2>&1 && echo "test_version Succeeded" VERBATIM)
index 842fd98..539d80c 100644 (file)
@@ -1,6 +1,7 @@
-#include <iostream>
+#include <test-harness.h>
+#include "tct-dali-shader-generator-core.h"
+
 int main(int argc, char * const argv[])
 {
-  std::cout << "All tests run as part of Cmake build." << std::endl;
-  return 0;
+  return TestHarness::RunTests(argc, argv, tc_array);
 }
diff --git a/automated-tests/src/dali-shader-generator/utc-Dali-ShaderGenerator.cpp b/automated-tests/src/dali-shader-generator/utc-Dali-ShaderGenerator.cpp
new file mode 100644 (file)
index 0000000..68fc2ab
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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>
+
+void utc_dali_shader_generator_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_shader_generator_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliShaderGenerator(void)
+{
+  tet_infoline("All tests run as part of cmake build");
+  DALI_TEST_CHECK(true);
+  END_TEST;
+}
index cc18fe6..0a65397 100755 (executable)
@@ -30,11 +30,13 @@ SET(TC_SOURCES
  utc-Dali-Text-ViewModel.cpp
  utc-Dali-TextField-internal.cpp
  utc-Dali-TextEditor-internal.cpp
+ utc-Dali-TextLabel-internal.cpp
  utc-Dali-TextSelectionPopup-internal.cpp
  utc-Dali-TextureManager.cpp
  utc-Dali-Visuals-internal.cpp
  utc-Dali-VisualModel.cpp
  utc-Dali-VisualUrl.cpp
+ utc-Dali-Text-Hyphen-Wrapping.cpp
 )
 
 IF(ELDBUS_AVAILABLE)
@@ -79,10 +81,12 @@ SET(TEST_HARNESS_SOURCES
    ../dali-toolkit/dali-toolkit-test-utils/test-button.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-harness.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.cpp
-   ../dali-toolkit/dali-toolkit-test-utils/test-gl-sync-abstraction.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-impl.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-object.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-buffer.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-command-buffer.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-graphics-framebuffer.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-texture.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-program.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-pipeline.cpp
index d98f397..0a426b0 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
 #include <dali-toolkit/internal/text/shaper.h>
 #include <dali-toolkit/internal/text/text-controller-impl.h>
 #include <dali-toolkit/internal/text/markup-processor.h>
+#include <dali-toolkit/internal/text/hyphenator.h>
 
 namespace Dali
 {
@@ -100,7 +101,8 @@ void CreateTextModel( const std::string& text,
                       Size& layoutSize,
                       ModelPtr& textModel,
                       MetricsPtr& metrics,
-                      bool markupProcessorEnabled )
+                      bool markupProcessorEnabled,
+                      LineWrap::Mode wrapMode )
 {
   textModel = Model::New(); ///< Pointer to the text's model.
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
@@ -109,7 +111,8 @@ void CreateTextModel( const std::string& text,
   MarkupProcessData markupProcessData( logicalModel->mColorRuns,
                                        logicalModel->mFontDescriptionRuns,
                                        logicalModel->mEmbeddedItems,
-                                       logicalModel->mAnchors );
+                                       logicalModel->mAnchors,
+                                       logicalModel->mUnderlinedCharacterRuns);
 
   Length textSize = 0u;
   const uint8_t* utf8 = NULL;
@@ -153,6 +156,41 @@ void CreateTextModel( const std::string& text,
     return;
   }
 
+  textModel->mLineWrapMode = wrapMode;
+
+  if(textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+       textModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
+  {
+    CharacterIndex end                 = characterCount;
+    LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
+
+    for(CharacterIndex index = 0; index < end; index++)
+    {
+      CharacterIndex wordEnd = index;
+      while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
+      {
+        wordEnd++;
+      }
+
+      if((wordEnd + 1) == end) // add last char
+      {
+        wordEnd++;
+      }
+
+      Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
+
+      for(CharacterIndex i = 0; i < (wordEnd - index); i++)
+      {
+        if(hyphens[i])
+        {
+          *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
+        }
+      }
+
+      index = wordEnd;
+    }
+  }
+
   // 3) Set the script info.
   MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
 
@@ -283,7 +321,6 @@ void CreateTextModel( const std::string& text,
 
   // Set the layout parameters.
   textModel->mHorizontalAlignment = Text::HorizontalAlignment::BEGIN;
-  textModel->mLineWrapMode = LineWrap::WORD;
   textModel->mIgnoreSpacesAfterText = true;
   textModel->mMatchSystemLanguageDirection = false;
   Layout::Parameters layoutParameters( textArea,
index eb0dd40..6e30bbb 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_TEXT_UTILS_H
 
 /*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -64,7 +64,8 @@ void CreateTextModel( const std::string& text,
                       Size& layoutSize,
                       ModelPtr& textModel,
                       MetricsPtr& metrics,
-                      bool markupProcessorEnabled );
+                      bool markupProcessorEnabled,
+                      LineWrap::Mode wrapMode );
 
 /**
  * @brief Configures the text @p controller similarly to the one configured by the text-label.
index c68e84f..fdd8f10 100644 (file)
@@ -460,6 +460,22 @@ int UtcDaliControlReadingInfoType(void)
   auto control = Control::New();
 
   auto reading_info_type = DevelControl::GetAccessibilityReadingInfoType(control);
+
+  for ( auto i = 0u; i < 4; ++i)
+    DALI_TEST_CHECK ( reading_info_type[ static_cast< Dali::Accessibility::ReadingInfoType >( i ) ]);
+
+  reading_info_type[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = false;
+  reading_info_type[Dali::Accessibility::ReadingInfoType::STATE] = false;
+  reading_info_type[Dali::Accessibility::ReadingInfoType::NAME] = false;
+  reading_info_type[Dali::Accessibility::ReadingInfoType::ROLE] = false;
+
+  DevelControl::SetAccessibilityReadingInfoType(control, reading_info_type);
+
+  reading_info_type = DevelControl::GetAccessibilityReadingInfoType(control);
+
+  for ( auto i = 0u; i < 4; ++i)
+    DALI_TEST_CHECK ( false == reading_info_type[ static_cast< Dali::Accessibility::ReadingInfoType >( i ) ]);
+
   reading_info_type[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
   reading_info_type[Dali::Accessibility::ReadingInfoType::STATE] = true;
   reading_info_type[Dali::Accessibility::ReadingInfoType::NAME] = true;
index f3d97a9..dabd012 100644 (file)
@@ -559,6 +559,13 @@ int UtcDaliAccessibilityTextField(void)
   DALI_TEST_EQUALS( text->SetSelection( 1, 0, 1 ), false, TEST_LOCATION );
   DALI_TEST_EQUALS( text->RemoveSelection( 1 ), false, TEST_LOCATION );
 
+  DALI_TEST_EQUALS(editabletext->SetTextContents("adef"), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(editabletext->InsertText(1, "bc"), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(text->GetText(0, 6), "abcdef", TEST_LOCATION);
+  DALI_TEST_EQUALS(editabletext->DeleteText(5, 1), false, TEST_LOCATION);
+  DALI_TEST_EQUALS(editabletext->DeleteText(1, 5), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(text->GetText(0, 2), "af", TEST_LOCATION);
+
   Dali::Accessibility::TestEnableSC( false );
 
   END_TEST;
@@ -608,6 +615,13 @@ int UtcDaliAccessibilityTextEditor(void)
   DALI_TEST_EQUALS( text->SetSelection( 1, 0, 1 ), false, TEST_LOCATION );
   DALI_TEST_EQUALS( text->RemoveSelection( 1 ), false, TEST_LOCATION );
 
+  DALI_TEST_EQUALS(editabletext->SetTextContents("adef"), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(editabletext->InsertText(1, "bc"), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(text->GetText(0, 6), "abcdef", TEST_LOCATION);
+  DALI_TEST_EQUALS(editabletext->DeleteText(5, 1), false, TEST_LOCATION);
+  DALI_TEST_EQUALS(editabletext->DeleteText(1, 5), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(text->GetText(0, 2), "af", TEST_LOCATION);
+
   Dali::Accessibility::TestEnableSC( false );
 
   END_TEST;
index e056f73..de772f3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -111,7 +111,8 @@ bool SetBidirectionalInfoTest( const SetBidirectionalInfoData& data )
                    layoutSize,
                    textModel,
                    metrics,
-                   false );
+                   false,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -196,7 +197,8 @@ bool GetMirroredTextTest( const GetMirroredTextData& data )
                    layoutSize,
                    textModel,
                    metrics,
-                   false );
+                   false,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -272,7 +274,8 @@ bool GetCharactersDirectionTest( const GetCharactersDirectionData& data )
                    layoutSize,
                    textModel,
                    metrics,
-                   data.markupProcessorEnabled );
+                   data.markupProcessorEnabled,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
index 7cbbe90..8515172 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -118,7 +118,8 @@ bool CreateParagraphTest( const CreateParagraphData& data )
                    layoutSize,
                    textModel,
                    metrics,
-                   false );
+                   false,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -180,7 +181,8 @@ bool FindParagraphTest( const FindParagraphData& data )
                    layoutSize,
                    textModel,
                    metrics,
-                   false );
+                   false,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -231,7 +233,8 @@ bool FetchBidirectionalLineInfoTest( const FetchBidirectionalLineInfoData& data
                    layoutSize,
                    textModel,
                    metrics,
-                   false );
+                   false,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -277,7 +280,8 @@ bool GetLogicalCharacterIndexTest( const GetLogicalCharacterIndexData& data )
                    layoutSize,
                    textModel,
                    metrics,
-                   false );
+                   false,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -340,7 +344,8 @@ bool GetLogicalCursorIndexTest( const GetLogicalCursorIndexData& data )
                    layoutSize,
                    textModel,
                    metrics,
-                   false );
+                   false,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
index 2ab84e7..78d7cf8 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -111,7 +111,8 @@ bool GetClosestLineTest( const GetClosestLineData& data )
                    layoutSize,
                    textModel,
                    metrics,
-                   false );
+                   false,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -157,7 +158,8 @@ bool GetClosestCursorIndexTest( const GetClosestCursorIndexData& data )
                    layoutSize,
                    textModel,
                    metrics,
-                   false );
+                   false,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -207,7 +209,8 @@ bool GetCursorPositionTest( const GetCursorPositionData& data )
                    layoutSize,
                    textModel,
                    metrics,
-                   false );
+                   false,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -260,7 +263,8 @@ bool FindSelectionIndicesTest( const FindSelectionIndicesData& data )
                    layoutSize,
                    textModel,
                    metrics,
-                   false );
+                   false,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Hyphen-Wrapping.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Hyphen-Wrapping.cpp
new file mode 100755 (executable)
index 0000000..ccc8463
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+
+namespace
+{
+
+const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+
+struct LayoutTextData
+{
+  std::string          text;
+  Size                 textArea;
+  unsigned int         numberOfFonts;
+  FontDescriptionRun  *fontDescriptions;
+  unsigned int         numberOfLines;
+  LineRun*             lines;
+  Layout::Engine::Type layout;
+  unsigned int         startIndex;
+  unsigned int         numberOfGlyphs;
+  Text::LineWrap::Mode wrapMode;
+};
+
+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;
+}
+
+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" );
+
+  // 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,
+                   data.wrapMode );
+
+  Vector<LineRun>& lines = textModel->mVisualModel->mLines;
+
+  // 4) Compare the results.
+
+  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.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;
+    }
+  }
+
+  return true;
+}
+
+} // namespace
+
+
+int UtcDaliTextHyphenWrapping(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextHyphenWrapping");
+
+  // 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 = 13u;
+  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;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun1 );
+  Size textArea(65.0f, 200.f);
+  
+  LineRun line1 =
+  {
+    { 0u, 5u },
+    { 0u, 5u },
+    0.f,
+    0.f,
+    0.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  LineRun line2 =
+  {
+    { 5u, 8u },
+    { 5u, 8u },
+    0.f,
+    0.f,
+    0.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  
+  Vector<LineRun> lines;
+  lines.PushBack( line1 );
+  lines.PushBack( line2 );
+
+  LayoutTextData data =
+  {
+    "Hi Experiment",
+    textArea,
+    1u,
+    fontDescriptionRuns.Begin(),
+    2u,
+    lines.Begin(),
+    Layout::Engine::MULTI_LINE_BOX,
+    0u,
+    13u,
+    (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextMixedWrapping(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextMixedWrapping");
+
+  // Layout some lines of left to right text.
+
+  const std::string fontFamily( "DejaVuSans" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun1;
+  fontDescriptionRun1.characterRun.characterIndex = 0u;
+  fontDescriptionRun1.characterRun.numberOfCharacters = 13u;
+  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;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun1 );
+  Size textArea(72.0f, 200.f);
+  
+  LineRun line1 =
+  {
+    { 0u, 3u },
+    { 0u, 3u },
+    0.f,
+    0.f,
+    0.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  LineRun line2 =
+  {
+    { 3u, 6u },
+    { 3u, 6u },
+    0.f,
+    0.f,
+    0.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  LineRun line3 =
+  {
+    { 9u, 4u },
+    { 9u, 4u },
+    0.f,
+    0.f,
+    0.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  
+  Vector<LineRun> lines;
+  lines.PushBack( line1 );
+  lines.PushBack( line2 );
+  lines.PushBack( line3 );
+
+  LayoutTextData data =
+  {
+    "Hi Experiment",
+    textArea,
+    1u,
+    fontDescriptionRuns.Begin(),
+    3u,
+    lines.Begin(),
+    Layout::Engine::MULTI_LINE_BOX,
+    0u,
+    13u,
+    (Text::LineWrap::Mode)DevelText::LineWrap::MIXED
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
\ No newline at end of file
index 05226d4..8bdecaa 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -108,7 +108,8 @@ bool LayoutTextTest( const LayoutTextData& data )
                    layoutSize,
                    textModel,
                    metrics,
-                   false );
+                   false,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -363,7 +364,8 @@ bool AlignTest( const AlignData& data )
                    layoutSize,
                    textModel,
                    metrics,
-                   false );
+                   false,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
index 6e2d632..f46c401 100755 (executable)
@@ -185,7 +185,8 @@ namespace
     Vector<FontDescriptionRun> fontRuns;
     Vector<EmbeddedItem> items;
     Vector<Anchor> anchors;
-    MarkupProcessData markupProcessData( colorRuns, fontRuns, items, anchors );
+    Vector<UnderlinedCharacterRun> underlinedCharacterRuns;
+    MarkupProcessData markupProcessData( colorRuns, fontRuns, items, anchors, underlinedCharacterRuns );
     ProcessMarkupString( data.xHTMLEntityString, markupProcessData );
 
     for( Vector<EmbeddedItem>::Iterator it = items.Begin(),
index a7534f9..52c8808 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -140,7 +140,8 @@ bool ShapeInfoTest( const ShapeInfoData& data )
                    layoutSize,
                    textModel,
                    metrics,
-                   false );
+                   false,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
index 9445be6..b19d653 100755 (executable)
@@ -21,6 +21,7 @@
 #include <dali-toolkit-test-suite-utils.h>
 #include <dali-toolkit/dali-toolkit.h>
 
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
 #include <dali-toolkit/internal/controls/text-controls/text-editor-impl.h>
 #include <dali-toolkit/internal/text/text-controller.h>
 #include <dali-toolkit/internal/text/text-controller-impl.h>
@@ -70,3 +71,100 @@ int UtcDaliTextEditorSelectText(void)
 
   END_TEST;
 }
+
+int UtcDaliTextEditorMarkupUnderline(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextEditorMarkupUnderline ");
+
+  TextEditor textEditor = TextEditor::New();
+
+  application.GetScene().Add( textEditor );
+
+  textEditor.SetProperty( TextEditor::Property::TEXT, "<u>ABC</u>EF<u>GH</u>" );
+  textEditor.SetProperty( TextEditor ::Property::ENABLE_MARKUP,  true );
+
+  application.SendNotification();
+  application.Render();
+
+  uint32_t expectedNumberOfUnderlinedGlyphs = 5u;
+
+  Toolkit::Internal::TextEditor& textEditorImpl = GetImpl( textEditor );
+  const Text::Length numberOfUnderlineRuns = textEditorImpl.getController()->GetTextModel()->GetNumberOfUnderlineRuns();
+
+  DALI_TEST_EQUALS( numberOfUnderlineRuns, expectedNumberOfUnderlinedGlyphs, TEST_LOCATION );
+
+  Vector<GlyphRun> underlineRuns;
+  underlineRuns.Resize(numberOfUnderlineRuns);
+  textEditorImpl.getController()->GetTextModel()->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
+
+  //ABC are underlined
+  DALI_TEST_EQUALS( underlineRuns[0u].glyphIndex, 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS( underlineRuns[1u].glyphIndex, 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS( underlineRuns[2u].glyphIndex, 2u, TEST_LOCATION);
+
+  //GH are underlined
+  DALI_TEST_EQUALS( underlineRuns[3u].glyphIndex, 5u, TEST_LOCATION);
+  DALI_TEST_EQUALS( underlineRuns[4u].glyphIndex, 6u, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliTextEditorFontPointSizeLargerThanAtlas(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextEditorFontPointSizeLargerThanAtlas ");
+
+  // Create a text editor
+  TextEditor textEditor = TextEditor::New();
+  //Set size to avoid automatic eliding
+  textEditor.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+  //Set very large font-size using point-size
+  textEditor.SetProperty( TextEditor::Property::POINT_SIZE, 1000);
+  //Specify font-family
+  textEditor.SetProperty( TextEditor::Property::FONT_FAMILY, "DejaVu Sans");
+  //Set text to check if appear or not
+  textEditor.SetProperty(TextEditor::Property::TEXT, "A");
+
+  application.GetScene().Add( textEditor );
+
+  application.SendNotification();
+  application.Render();
+
+  //Check if Glyph is added to AtlasGlyphManger or not
+  int countAtlas = AtlasGlyphManager::Get().GetMetrics().mAtlasMetrics.mAtlasCount;
+  DALI_TEST_EQUALS( countAtlas, 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliTextEditorFontPointSizeLargerThanAtlasPlaceholderCase(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextEditorFontPointSizeLargerThanAtlasPlaceholderCase ");
+
+  //Set Map of placeholder: text, font-family and point-size
+  Property::Map placeholderMapSet;
+  placeholderMapSet["text"] = "A";
+  placeholderMapSet["fontFamily"] = "DejaVu Sans";
+  placeholderMapSet["pixelSize"] = 1000.0f;
+
+  // Create a text editor
+  TextEditor textEditor = TextEditor::New();
+  //Set size to avoid automatic eliding
+  textEditor.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+  //Set placeholder
+  textEditor.SetProperty( TextEditor::Property::PLACEHOLDER, placeholderMapSet) ;
+
+  application.GetScene().Add( textEditor );
+
+  application.SendNotification();
+  application.Render();
+
+  //Check if Glyph is added to AtlasGlyphManger or not
+  int countAtlas = AtlasGlyphManager::Get().GetMetrics().mAtlasMetrics.mAtlasCount;
+  DALI_TEST_EQUALS( countAtlas, 1, TEST_LOCATION );
+
+  END_TEST;
+}
\ No newline at end of file
index 37d54e1..619e5f4 100755 (executable)
@@ -21,6 +21,7 @@
 #include <dali-toolkit-test-suite-utils.h>
 #include <dali-toolkit/dali-toolkit.h>
 
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.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>
@@ -152,3 +153,102 @@ int UtcDaliTextFieldSelectText(void)
 
   END_TEST;
 }
+
+int UtcDaliTextFieldMarkupUnderline(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextFieldMarkupUnderline ");
+
+  TextField textField = TextField::New();
+
+  application.GetScene().Add( textField );
+
+  textField.SetProperty( TextField::Property::TEXT, "<u>ABC</u>EF<u>GH</u>" );
+  textField.SetProperty( TextField ::Property::ENABLE_MARKUP,  true );
+
+  application.SendNotification();
+  application.Render();
+
+  uint32_t expectedNumberOfUnderlinedGlyphs = 5u;
+
+  Toolkit::Internal::TextField& textFieldImpl = GetImpl( textField );
+  const Text::Length numberOfUnderlineRuns = textFieldImpl.getController()->GetTextModel()->GetNumberOfUnderlineRuns();
+
+  DALI_TEST_EQUALS( numberOfUnderlineRuns, expectedNumberOfUnderlinedGlyphs, TEST_LOCATION );
+
+  Vector<GlyphRun> underlineRuns;
+  underlineRuns.Resize(numberOfUnderlineRuns);
+  textFieldImpl.getController()->GetTextModel()->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
+
+  //ABC are underlined
+  DALI_TEST_EQUALS( underlineRuns[0u].glyphIndex, 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS( underlineRuns[1u].glyphIndex, 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS( underlineRuns[2u].glyphIndex, 2u, TEST_LOCATION);
+
+  //GH are underlined
+  DALI_TEST_EQUALS( underlineRuns[3u].glyphIndex, 5u, TEST_LOCATION);
+  DALI_TEST_EQUALS( underlineRuns[4u].glyphIndex, 6u, TEST_LOCATION);
+
+  END_TEST;
+
+}
+
+int UtcDaliTextFieldFontPointSizeLargerThanAtlas(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextFieldFontPointSizeLargerThanAtlas ");
+
+  // Create a Text field
+  TextField textField = TextField::New();
+  //Set size to avoid automatic eliding
+  textField.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+  //Set very large font-size using point-size
+  textField.SetProperty( TextField::Property::POINT_SIZE, 1000) ;
+  //Specify font-family
+  textField.SetProperty( TextField::Property::FONT_FAMILY, "DejaVu Sans");
+  //Set text to check if appear or not
+  textField.SetProperty( TextField::Property::TEXT, "A");
+
+  application.GetScene().Add( textField );
+
+  application.SendNotification();
+  application.Render();
+
+  //Check if Glyph is added to AtlasGlyphManger or not
+  int countAtlas = AtlasGlyphManager::Get().GetMetrics().mAtlasMetrics.mAtlasCount;
+  DALI_TEST_EQUALS( countAtlas, 1, TEST_LOCATION );
+
+
+  END_TEST;
+}
+
+int UtcDaliTextFieldFontPointSizeLargerThanAtlasPlaceholderCase(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextFieldFontPointSizeLargerThanAtlasPlaceholderCase ");
+
+  //Set Map of placeholder: text, font-family and point-size
+  Property::Map placeholderMapSet;
+  placeholderMapSet["text"] = "A";
+  placeholderMapSet["fontFamily"] = "DejaVu Sans";
+  placeholderMapSet["pixelSize"] = 1000.0f;
+
+  // Create a text editor
+  TextField textField = TextField::New();
+  //Set size to avoid automatic eliding
+  textField.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+  //Set placeholder
+  textField.SetProperty( TextField::Property::PLACEHOLDER, placeholderMapSet) ;
+
+  application.GetScene().Add( textField );
+
+  application.SendNotification();
+  application.Render();
+
+  //Check if Glyph is added to AtlasGlyphManger or not
+  int countAtlas = AtlasGlyphManager::Get().GetMetrics().mAtlasMetrics.mAtlasCount;
+  DALI_TEST_EQUALS( countAtlas, 1, TEST_LOCATION );
+
+
+  END_TEST;
+}
\ No newline at end of file
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextLabel-internal.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextLabel-internal.cpp
new file mode 100755 (executable)
index 0000000..e85ea21
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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/dali-toolkit.h>
+
+#include <dali-toolkit/internal/controls/text-controls/text-label-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 UtcDaliTextLabelMarkupUnderline(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLabelMarkupUnderline ");
+
+  TextLabel textLabel = TextLabel::New();
+
+  application.GetScene().Add( textLabel );
+
+  textLabel.SetProperty( TextLabel::Property::TEXT, "<u>ABC</u>EF<u>GH</u>" );
+  textLabel.SetProperty( TextLabel ::Property::ENABLE_MARKUP,  true );
+
+  application.SendNotification();
+  application.Render();
+
+  uint32_t expectedNumberOfUnderlinedGlyphs = 5u;
+
+  Toolkit::Internal::TextLabel& textLabelImpl = GetImpl( textLabel );
+  const Text::Length numberOfUnderlineRuns = textLabelImpl.getController()->GetTextModel()->GetNumberOfUnderlineRuns();
+
+  DALI_TEST_EQUALS( numberOfUnderlineRuns, expectedNumberOfUnderlinedGlyphs, TEST_LOCATION );
+
+  Vector<GlyphRun> underlineRuns;
+  underlineRuns.Resize(numberOfUnderlineRuns);
+  textLabelImpl.getController()->GetTextModel()->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
+
+  //ABC are underlined
+  DALI_TEST_EQUALS( underlineRuns[0u].glyphIndex, 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS( underlineRuns[1u].glyphIndex, 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS( underlineRuns[2u].glyphIndex, 2u, TEST_LOCATION);
+
+  //GH are underlined
+  DALI_TEST_EQUALS( underlineRuns[3u].glyphIndex, 5u, TEST_LOCATION);
+  DALI_TEST_EQUALS( underlineRuns[4u].glyphIndex, 6u, TEST_LOCATION);
+
+  END_TEST;
+
+}
\ No newline at end of file
index df247e0..43157ff 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -79,7 +79,8 @@ bool SetGlyphsPerCharacterTest( const SetGlyphsPerCharacterData& data )
                    layoutSize,
                    textModel,
                    metrics,
-                   false );
+                   false,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -163,7 +164,8 @@ bool SetCharacterToGlyphTest( const SetCharacterToGlyphData& data )
                    layoutSize,
                    textModel,
                    metrics,
-                   false );
+                   false,
+                   LineWrap::WORD );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
index cc1488e..4c211d1 100644 (file)
@@ -45,10 +45,12 @@ SET(TEST_HARNESS_SOURCES
    ../dali-toolkit/dali-toolkit-test-utils/test-application.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-platform-abstraction.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.cpp
-   ../dali-toolkit/dali-toolkit-test-utils/test-gl-sync-abstraction.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-impl.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-object.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-buffer.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-command-buffer.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-graphics-framebuffer.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-texture.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-pipeline.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-program.cpp
index 820a4a5..e30acba 100644 (file)
@@ -31,10 +31,12 @@ SET(TEST_HARNESS_SOURCES
    ../dali-toolkit/dali-toolkit-test-utils/test-button.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-harness.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.cpp
-   ../dali-toolkit/dali-toolkit-test-utils/test-gl-sync-abstraction.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-impl.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-object.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-buffer.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-command-buffer.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-graphics-framebuffer.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-texture.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-sampler.cpp
    ../dali-toolkit/dali-toolkit-test-utils/test-graphics-pipeline.cpp
index c3ab255..2983fd7 100755 (executable)
@@ -112,10 +112,12 @@ SET(TEST_HARNESS_SOURCES
   dali-toolkit-test-utils/test-harness.cpp
   dali-toolkit-test-utils/test-gesture-generator.cpp
   dali-toolkit-test-utils/test-gl-abstraction.cpp
-  dali-toolkit-test-utils/test-gl-sync-abstraction.cpp
+  dali-toolkit-test-utils/test-graphics-sync-impl.cpp
+  dali-toolkit-test-utils/test-graphics-sync-object.cpp
   dali-toolkit-test-utils/test-graphics-buffer.cpp
   dali-toolkit-test-utils/test-graphics-command-buffer.cpp
   dali-toolkit-test-utils/test-graphics-controller.cpp
+  dali-toolkit-test-utils/test-graphics-framebuffer.cpp
   dali-toolkit-test-utils/test-graphics-texture.cpp
   dali-toolkit-test-utils/test-graphics-pipeline.cpp
   dali-toolkit-test-utils/test-graphics-program.cpp
index 2db4dbc..bf62bb8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -91,4 +91,44 @@ Actor CreateRenderableActor(Texture texture, const std::string& vertexShader, co
   return actor;
 }
 
+Actor CreateRenderableActor2(TextureSet textures, 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(textures)
+  {
+    renderer.SetTextures(textures);
+
+    auto texture = textures.GetTexture(0);
+
+    // Set actor to the size of the texture if set
+    actor.SetProperty(Actor::Property::SIZE, Vector2(texture.GetWidth(), texture.GetHeight()));
+  }
+
+  return actor;
+}
+
+Texture CreateTexture(TextureType::Type type, Pixel::Format format, int width, int height)
+{
+  Texture texture = Texture::New(type, format, width, height);
+
+  int       bufferSize = width * height * 2;
+  uint8_t*  buffer     = reinterpret_cast<uint8_t*>(malloc(bufferSize));
+  PixelData pixelData  = PixelData::New(buffer, bufferSize, width, height, format, PixelData::FREE);
+  texture.Upload(pixelData, 0u, 0u, 0u, 0u, width, height);
+  return texture;
+}
+
 } // namespace Dali
index be085bf..0dbe07e 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TEST_ACTOR_UTILS_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,6 +19,8 @@
  */
 
 // EXTERNAL INCLUDES
+#include <dali/public-api/rendering/texture-set.h>
+#include <dali/public-api/rendering/texture.h>
 #include <string>
 
 namespace Dali
@@ -49,6 +51,17 @@ Actor CreateRenderableActor(Texture texture);
  */
 Actor CreateRenderableActor(Texture texture, const std::string& vertexShader, const std::string& fragmentShader);
 
+/**
+ * @brief Creates a renderable-actor with a texture and custom shaders.
+ * @param[in] textures TextureSet to set.
+ * @param[in] vertexShader The vertex-shader.
+ * @param[in] fragmentShader The fragment-shader.
+ * @return An actor with a renderer.
+ */
+Actor CreateRenderableActor2(TextureSet textures, const std::string& vertexShader, const std::string& fragmentShader);
+
+Texture CreateTexture(TextureType::Type type, Pixel::Format format, int width, int height);
+
 } // namespace Dali
 
 #endif // DALI_TEST_ACTOR_UTILS_H
index a2a1848..5e69c95 100644 (file)
@@ -76,6 +76,12 @@ 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)));
+
+  // Create render target for the scene
+  Graphics::RenderTargetCreateInfo rtInfo{};
+  rtInfo.SetExtent({mSurfaceWidth, mSurfaceHeight});
+  mRenderTarget = mGraphicsController.CreateRenderTarget(rtInfo, nullptr);
+  mScene.SetSurfaceRenderTarget(mRenderTarget.get());
 }
 
 void TestApplication::InitializeCore()
@@ -149,14 +155,14 @@ TestGlAbstraction& TestApplication::GetGlAbstraction()
   return static_cast<TestGlAbstraction&>(mGraphicsController.GetGlAbstraction());
 }
 
-TestGlSyncAbstraction& TestApplication::GetGlSyncAbstraction()
+TestGlContextHelperAbstraction& TestApplication::GetGlContextHelperAbstraction()
 {
-  return static_cast<TestGlSyncAbstraction&>(mGraphicsController.GetGlSyncAbstraction());
+  return static_cast<TestGlContextHelperAbstraction&>(mGraphicsController.GetGlContextHelperAbstraction());
 }
 
-TestGlContextHelperAbstraction& TestApplication::GetGlContextHelperAbstraction()
+TestGraphicsSyncImplementation& TestApplication::GetGraphicsSyncImpl()
 {
-  return static_cast<TestGlContextHelperAbstraction&>(mGraphicsController.GetGlContextHelperAbstraction());
+  return static_cast<TestGraphicsSyncImplementation&>(mGraphicsController.GetGraphicsSyncImpl());
 }
 
 void TestApplication::ProcessEvent(const Integration::Event& event)
index e7d8c76..4f32cd8 100644 (file)
@@ -65,8 +65,8 @@ public:
   TestGraphicsController&  GetGraphicsController();
 
   TestGlAbstraction&              GetGlAbstraction();
-  TestGlSyncAbstraction&          GetGlSyncAbstraction();
   TestGlContextHelperAbstraction& GetGlContextHelperAbstraction();
+  TestGraphicsSyncImplementation& GetGraphicsSyncImpl();
 
   void        ProcessEvent(const Integration::Event& event);
   void        SendNotification();
@@ -108,6 +108,8 @@ protected:
   uint32_t mSurfaceHeight;
   uint32_t mFrame;
 
+  Graphics::UniquePtr<Graphics::RenderTarget> mRenderTarget;
+
   struct
   {
     uint32_t x;
index f2086d6..b85cf4d 100644 (file)
 #include "test-gl-abstraction.h"
 #include "test-trace-call-stack.h"
 
+static const bool TRACE{
+  false};
+
 namespace Dali
 {
 TestGlAbstraction::TestGlAbstraction()
-: mBufferTrace(true, std::string("gl")),
-  mCullFaceTrace(true, "gl"),
-  mEnableDisableTrace(true, "gl"),
-  mShaderTrace(true, "gl"),
-  mTextureTrace(true, std::string("gl")),
-  mTexParameterTrace(true, "gl"),
-  mDrawTrace(true, "gl"),
-  mDepthFunctionTrace(true, "gl"),
-  mStencilFunctionTrace(true, "gl"),
-  mScissorTrace(true, "gl"),
-  mSetUniformTrace(true, "Uniform "),
-  mViewportTrace(true, "gl")
+: mBufferTrace(TRACE, std::string("gl")),
+  mCullFaceTrace(TRACE, "gl"),
+  mEnableDisableTrace(TRACE, "gl"),
+  mShaderTrace(TRACE, "gl"),
+  mTextureTrace(TRACE, std::string("gl")),
+  mTexParameterTrace(TRACE, "gl"),
+  mDrawTrace(TRACE, "gl"),
+  mDepthFunctionTrace(TRACE, "gl"),
+  mStencilFunctionTrace(TRACE, "gl"),
+  mScissorTrace(TRACE, "gl"),
+  mSetUniformTrace(TRACE, "Uniform "),
+  mViewportTrace(TRACE, "gl")
 {
   Initialize();
 }
@@ -46,7 +49,6 @@ void TestGlAbstraction::Initialize()
   mCurrentProgram                  = 0;
   mCompileStatus                   = GL_TRUE;
   mLinkStatus                      = GL_TRUE;
-  mNumberOfActiveUniforms          = 0;
   mGetErrorResult                  = 0;
   mGetStringResult                 = NULL;
   mIsBufferResult                  = 0;
@@ -112,6 +114,31 @@ void TestGlAbstraction::Initialize()
   {
     mVertexAttribArrayState[i] = false;
   }
+
+  mActiveUniforms = std::vector<ActiveUniform>{
+    {"uRendererColor", GL_FLOAT, 1},
+    {"uCustom", GL_FLOAT_VEC3, 1},
+    {"uCustom3", GL_FLOAT_VEC3, 1},
+    {"uFadeColor", GL_FLOAT_VEC4, 1},
+    {"uUniform1", GL_FLOAT_VEC4, 1},
+    {"uUniform2", GL_FLOAT_VEC4, 1},
+    {"uUniform3", GL_FLOAT_VEC4, 1},
+    {"uFadeProgress", GL_FLOAT, 1},
+    {"uANormalMatrix", GL_FLOAT_MAT3, 1},
+    {"sEffect", GL_SAMPLER_2D, 1},
+    {"sTexture", GL_SAMPLER_2D, 1},
+    {"sTextureRect", GL_SAMPLER_2D, 1},
+    {"sGloss", GL_SAMPLER_2D, 1},
+    {"uColor", GL_FLOAT_VEC4, 1},
+    {"uModelMatrix", GL_FLOAT_MAT4, 1},
+    {"uModelView", GL_FLOAT_MAT4, 1},
+    {"uMvpMatrix", GL_FLOAT_MAT4, 1},
+    {"uNormalMatrix", GL_FLOAT_MAT4, 1},
+    {"uProjection", GL_FLOAT_MAT4, 1},
+    {"uSize", GL_FLOAT_VEC3, 1},
+    {"uViewMatrix", GL_FLOAT_MAT4, 1},
+    {"uLightCameraProjectionMatrix", GL_FLOAT_MAT4, 1},
+    {"uLightCameraViewMatrix", GL_FLOAT_MAT4, 1}};
 }
 
 void TestGlAbstraction::PreRender()
index 9357803..aec9f5d 100644 (file)
@@ -49,6 +49,13 @@ struct UniformData
   }
 };
 
+struct ActiveUniform
+{
+  std::string name;
+  GLenum      type;
+  GLint       size;
+};
+
 class DALI_CORE_API TestGlAbstraction : public Dali::Integration::GlAbstraction
 {
 public:
@@ -621,6 +628,11 @@ public:
     {
       mFramebufferStencilAttached = true;
     }
+    else if(attachment == GL_DEPTH_STENCIL_ATTACHMENT)
+    {
+      mFramebufferStencilAttached = true;
+      mFramebufferDepthAttached   = true;
+    }
   }
 
   inline void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) override
@@ -749,27 +761,18 @@ public:
   {
   }
 
+  inline void SetActiveUniforms(const std::vector<ActiveUniform>& uniforms)
+  {
+    mActiveUniforms = uniforms;
+  }
+
   inline void GetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) override
   {
-    switch(index)
+    if(index < mActiveUniforms.size())
     {
-      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;
+      *length = snprintf(name, bufsize, "%s", mActiveUniforms[index].name.c_str());
+      *type   = mActiveUniforms[index].type;
+      *size   = mActiveUniforms[index].size;
     }
   }
 
@@ -837,7 +840,7 @@ public:
         *params = mProgramBinaryLength;
         break;
       case GL_ACTIVE_UNIFORMS:
-        *params = mNumberOfActiveUniforms;
+        *params = mActiveUniforms.size();
         break;
       case GL_ACTIVE_UNIFORM_MAX_LENGTH:
         *params = 100;
@@ -981,31 +984,10 @@ public:
     namedParams["program"] << program;
     mShaderTrace.PushCall("LinkProgram", out.str(), namedParams);
 
-    mNumberOfActiveUniforms = 3;
-
-    GetUniformLocation(program, "uRendererColor");
-    GetUniformLocation(program, "uCustom");
-    GetUniformLocation(program, "uCustom3");
-    GetUniformLocation(program, "uFadeColor");
-    GetUniformLocation(program, "uUniform1");
-    GetUniformLocation(program, "uUniform2");
-    GetUniformLocation(program, "uUniform3");
-    GetUniformLocation(program, "uFadeProgress");
-    GetUniformLocation(program, "uANormalMatrix");
-    GetUniformLocation(program, "sEffect");
-    GetUniformLocation(program, "sTexture");
-    GetUniformLocation(program, "sTextureRect");
-    GetUniformLocation(program, "sGloss");
-    GetUniformLocation(program, "uColor");
-    GetUniformLocation(program, "uModelMatrix");
-    GetUniformLocation(program, "uModelView");
-    GetUniformLocation(program, "uMvpMatrix");
-    GetUniformLocation(program, "uNormalMatrix");
-    GetUniformLocation(program, "uProjection");
-    GetUniformLocation(program, "uSize");
-    GetUniformLocation(program, "uViewMatrix");
-    GetUniformLocation(program, "uLightCameraProjectionMatrix");
-    GetUniformLocation(program, "uLightCameraViewMatrix");
+    for(const auto& uniform : mActiveUniforms)
+    {
+      GetUniformLocation(program, uniform.name.c_str());
+    }
 
     for(const auto& uniform : mCustomUniformData)
     {
@@ -2465,14 +2447,13 @@ public: // TEST FUNCTIONS
     mBufferSubDataCalls.clear();
   }
 
-private:
+public:
   GLuint                                mCurrentProgram;
   GLuint                                mCompileStatus;
   BufferDataCalls                       mBufferDataCalls;
   BufferSubDataCalls                    mBufferSubDataCalls;
   GLvoid*                               mMappedBuffer{nullptr};
   GLuint                                mLinkStatus;
-  GLint                                 mNumberOfActiveUniforms;
   GLenum                                mGetErrorResult;
   GLubyte*                              mGetStringResult;
   GLboolean                             mIsBufferResult;
@@ -2547,8 +2528,8 @@ private:
   typedef std::map<std::string, GLint>   UniformIDMap;
   typedef std::map<GLuint, UniformIDMap> ProgramUniformMap;
   ProgramUniformMap                      mUniforms;
-
-  std::vector<UniformData> mCustomUniformData{};
+  std::vector<ActiveUniform>             mActiveUniforms;
+  std::vector<UniformData>               mCustomUniformData{};
 
   template<typename T>
   struct ProgramUniformValue : public std::map<GLuint, std::map<GLint, T> >
index d8a1b1a..21eecf4 100644 (file)
@@ -80,14 +80,15 @@ GLenum TestGraphicsBuffer::GetTarget()
   return target;
 }
 
-void TestGraphicsBuffer::BindAsUniformBuffer(const TestGraphicsProgram* program) const
+void TestGraphicsBuffer::BindAsUniformBuffer(const TestGraphicsProgram* program, const Dali::UniformBufferBindingDescriptor& uboBinding) const
 {
   auto* reflection = static_cast<const TestGraphicsReflection*>(&program->GetReflection());
 
   Graphics::UniformBlockInfo uboInfo{};
   reflection->GetUniformBlock(0, uboInfo);
 
-  auto* data = memory.data();
+  auto  offset = uboBinding.offset;
+  auto* data   = memory.data() + offset;
 
   for(const auto& member : uboInfo.members)
   {
index 87c9f87..1dc2715 100644 (file)
@@ -26,6 +26,7 @@
 namespace Dali
 {
 class TestGraphicsProgram;
+class UniformBufferBindingDescriptor;
 class TestGraphicsBuffer : public Graphics::Buffer
 {
 public:
@@ -40,7 +41,7 @@ public:
     return true;
   }
 
-  void BindAsUniformBuffer(const TestGraphicsProgram* program) const;
+  void BindAsUniformBuffer(const TestGraphicsProgram* program, const Dali::UniformBufferBindingDescriptor& uboBinding) const;
 
   TraceCallStack&            mCallStack;
   TestGlAbstraction&         mGl;
index ed63416..9f86b99 100644 (file)
 
 namespace Dali
 {
+std::ostream& operator<<(std::ostream& os, Graphics::StencilOp op)
+{
+  switch(op)
+  {
+    case Graphics::StencilOp::KEEP:
+      os << "KEEP";
+      return os;
+    case Graphics::StencilOp::ZERO:
+      os << "ZERO";
+      return os;
+    case Graphics::StencilOp::REPLACE:
+      os << "REPLACE";
+      return os;
+    case Graphics::StencilOp::INCREMENT_AND_CLAMP:
+      os << "INCREMENT_AND_CLAMP";
+      return os;
+    case Graphics::StencilOp::DECREMENT_AND_CLAMP:
+      os << "DECREMENT_AND_CLAMP";
+      return os;
+    case Graphics::StencilOp::INVERT:
+      os << "INVERT";
+      return os;
+    case Graphics::StencilOp::INCREMENT_AND_WRAP:
+      os << "INCREMENT_AND_WRAP";
+      return os;
+    case Graphics::StencilOp::DECREMENT_AND_WRAP:
+      os << "DECREMENT_AND_WRAP";
+      return os;
+  }
+  return os;
+};
+
+std::ostream& operator<<(std::ostream& os, Graphics::CompareOp op)
+{
+  switch(op)
+  {
+    case Graphics::CompareOp::NEVER:
+      os << "NEVER";
+      return os;
+    case Graphics::CompareOp::LESS:
+      os << "LESS";
+      return os;
+    case Graphics::CompareOp::EQUAL:
+      os << "EQUAL";
+      return os;
+    case Graphics::CompareOp::LESS_OR_EQUAL:
+      os << "LESS_OR_EQUAL";
+      return os;
+    case Graphics::CompareOp::GREATER:
+      os << "GREATER";
+      return os;
+    case Graphics::CompareOp::NOT_EQUAL:
+      os << "NOT_EQUAL";
+      return os;
+    case Graphics::CompareOp::GREATER_OR_EQUAL:
+      os << "GREATER_OR_EQUAL";
+      return os;
+    case Graphics::CompareOp::ALWAYS:
+      os << "ALWAYS";
+      return os;
+  }
+  return os;
+};
+
 TestGraphicsCommandBuffer::TestGraphicsCommandBuffer(TraceCallStack& callstack, TestGlAbstraction& glAbstraction)
 : mCallStack(callstack),
   mGlAbstraction(glAbstraction)
@@ -60,9 +124,9 @@ void TestGraphicsCommandBuffer::GetStateForDrawCall(int drawCallIndex)
   }
 }
 
-std::vector<Command*> TestGraphicsCommandBuffer::GetCommandsByType(CommandTypeMask mask)
+std::vector<const Command*> TestGraphicsCommandBuffer::GetCommandsByType(CommandTypeMask mask) const
 {
-  std::vector<Command*> mCommandStack{};
+  std::vector<const Command*> mCommandStack{};
   for(auto& cmd : mCommands)
   {
     if(uint32_t(cmd.type) == (mask & uint32_t(cmd.type)))
@@ -73,4 +137,27 @@ std::vector<Command*> TestGraphicsCommandBuffer::GetCommandsByType(CommandTypeMa
   return mCommandStack;
 }
 
+std::vector<const Command*> TestGraphicsCommandBuffer::GetChildCommandsByType(CommandTypeMask mask) const
+{
+  std::vector<const Command*> mCommandStack{};
+  for(auto& cmd : mCommands)
+  {
+    if(uint32_t(cmd.type) == (mask & uint32_t(cmd.type)))
+    {
+      mCommandStack.emplace_back(&cmd);
+    }
+    if(cmd.type == CommandType::EXECUTE_COMMAND_BUFFERS)
+    {
+      for(auto secondaryCB : cmd.data.executeCommandBuffers.buffers)
+      {
+        for(auto command : secondaryCB->GetChildCommandsByType(mask))
+        {
+          mCommandStack.push_back(command);
+        }
+      }
+    }
+  }
+  return mCommandStack;
+}
+
 } // namespace Dali
index c10c3f1..3df3219 100644 (file)
@@ -32,27 +32,45 @@ namespace Dali
 {
 class TestGraphicsTexture;
 class TestGraphicsBuffer;
+class TestGraphicsCommandBuffer;
 class TestGraphicsSampler;
 class TestGraphicsPipeline;
 
 enum class CommandType
 {
-  FLUSH                 = 1 << 0,
-  BIND_TEXTURES         = 1 << 1,
-  BIND_SAMPLERS         = 1 << 2,
-  BIND_VERTEX_BUFFERS   = 1 << 3,
-  BIND_INDEX_BUFFER     = 1 << 4,
-  BIND_UNIFORM_BUFFER   = 1 << 5,
-  BIND_PIPELINE         = 1 << 6,
-  DRAW                  = 1 << 7,
-  DRAW_INDEXED          = 1 << 8,
-  DRAW_INDEXED_INDIRECT = 1 << 9,
-  SET_SCISSOR           = 1 << 10,
-  SET_SCISSOR_TEST      = 1 << 11,
-  SET_VIEWPORT          = 1 << 12,
-  SET_VIEWPORT_TEST     = 1 << 13
+  FLUSH                   = 1 << 0,
+  BIND_TEXTURES           = 1 << 1,
+  BIND_SAMPLERS           = 1 << 2,
+  BIND_VERTEX_BUFFERS     = 1 << 3,
+  BIND_INDEX_BUFFER       = 1 << 4,
+  BIND_UNIFORM_BUFFER     = 1 << 5,
+  BIND_PIPELINE           = 1 << 6,
+  DRAW                    = 1 << 7,
+  DRAW_INDEXED            = 1 << 8,
+  DRAW_INDEXED_INDIRECT   = 1 << 9,
+  SET_SCISSOR             = 1 << 10,
+  SET_SCISSOR_TEST        = 1 << 11,
+  SET_VIEWPORT            = 1 << 12,
+  SET_VIEWPORT_TEST       = 1 << 13,
+  BEGIN_RENDER_PASS       = 1 << 14,
+  END_RENDER_PASS         = 1 << 15,
+  EXECUTE_COMMAND_BUFFERS = 1 << 16,
+  SET_COLOR_MASK          = 1 << 17,
+  CLEAR_STENCIL_BUFFER    = 1 << 18,
+  CLEAR_DEPTH_BUFFER      = 1 << 19,
+  SET_STENCIL_TEST_ENABLE = 1 << 20,
+  SET_STENCIL_WRITE_MASK  = 1 << 21,
+  SET_STENCIL_OP          = 1 << 22,
+  SET_STENCIL_FUNC        = 1 << 23,
+  SET_DEPTH_COMPARE_OP    = 1 << 24,
+  SET_DEPTH_TEST_ENABLE   = 1 << 25,
+  SET_DEPTH_WRITE_ENABLE  = 1 << 26,
 };
 
+std::ostream& operator<<(std::ostream& os, Graphics::StencilOp op);
+
+std::ostream& operator<<(std::ostream& os, Graphics::CompareOp op);
+
 using CommandTypeMask = uint32_t;
 template<typename T>
 inline CommandTypeMask operator|(T flags, CommandType bit)
@@ -160,8 +178,37 @@ struct Command
   {
   }
 
+  Command(CommandType type)
+  : type(type)
+  {
+    // do non-trivial initialization
+    switch(type)
+    {
+      case CommandType::BEGIN_RENDER_PASS:
+      {
+        new(&data.beginRenderPass) CommandData::BeginRenderPassDescriptor();
+        break;
+      }
+      default:
+      {
+      }
+    }
+  }
+
   ~Command()
   {
+    switch(type)
+    {
+      case CommandType::BEGIN_RENDER_PASS:
+      {
+        data.beginRenderPass.~BeginRenderPassDescriptor();
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
   }
 
   /**
@@ -172,6 +219,22 @@ struct Command
   {
     switch(rhs.type)
     {
+      case CommandType::BEGIN_RENDER_PASS:
+      {
+        new(&data.beginRenderPass) CommandData::BeginRenderPassDescriptor(rhs.data.beginRenderPass);
+        break;
+      }
+      case CommandType::END_RENDER_PASS:
+      {
+        data.endRenderPass = rhs.data.endRenderPass;
+        break;
+      }
+      case CommandType::EXECUTE_COMMAND_BUFFERS:
+      {
+        data.executeCommandBuffers = rhs.data.executeCommandBuffers;
+        break;
+      }
+
       case CommandType::BIND_VERTEX_BUFFERS:
       {
         data.bindVertexBuffers = rhs.data.bindVertexBuffers;
@@ -245,6 +308,59 @@ struct Command
         data.viewportTest.enable = rhs.data.viewportTest.enable;
         break;
       }
+      case CommandType::SET_COLOR_MASK:
+      {
+        data.colorMask.enabled = rhs.data.colorMask.enabled;
+        break;
+      }
+      case CommandType::CLEAR_STENCIL_BUFFER:
+      {
+        break;
+      }
+      case CommandType::CLEAR_DEPTH_BUFFER:
+      {
+        break;
+      }
+      case CommandType::SET_STENCIL_TEST_ENABLE:
+      {
+        data.stencilTest.enabled = rhs.data.stencilTest.enabled;
+        break;
+      }
+      case CommandType::SET_STENCIL_FUNC:
+      {
+        data.stencilFunc.compareMask = rhs.data.stencilFunc.compareMask;
+        data.stencilFunc.compareOp   = rhs.data.stencilFunc.compareOp;
+        data.stencilFunc.reference   = rhs.data.stencilFunc.reference;
+        break;
+      }
+      case CommandType::SET_STENCIL_WRITE_MASK:
+      {
+        data.stencilWriteMask.mask = rhs.data.stencilWriteMask.mask;
+        break;
+      }
+      case CommandType::SET_STENCIL_OP:
+      {
+        data.stencilOp.failOp      = rhs.data.stencilOp.failOp;
+        data.stencilOp.depthFailOp = rhs.data.stencilOp.depthFailOp;
+        data.stencilOp.passOp      = rhs.data.stencilOp.passOp;
+        break;
+      }
+
+      case CommandType::SET_DEPTH_COMPARE_OP:
+      {
+        data.depth.compareOp = rhs.data.depth.compareOp;
+        break;
+      }
+      case CommandType::SET_DEPTH_TEST_ENABLE:
+      {
+        data.depth.testEnabled = rhs.data.depth.testEnabled;
+        break;
+      }
+      case CommandType::SET_DEPTH_WRITE_ENABLE:
+      {
+        data.depth.writeEnabled = rhs.data.depth.writeEnabled;
+        break;
+      }
     }
     type = rhs.type;
   }
@@ -257,6 +373,21 @@ struct Command
   {
     switch(rhs.type)
     {
+      case CommandType::BEGIN_RENDER_PASS:
+      {
+        new(&data.beginRenderPass) CommandData::BeginRenderPassDescriptor(std::move(rhs.data.beginRenderPass));
+        break;
+      }
+      case CommandType::END_RENDER_PASS:
+      {
+        data.endRenderPass = std::move(rhs.data.endRenderPass);
+        break;
+      }
+      case CommandType::EXECUTE_COMMAND_BUFFERS:
+      {
+        data.executeCommandBuffers = std::move(rhs.data.executeCommandBuffers);
+        break;
+      }
       case CommandType::BIND_VERTEX_BUFFERS:
       {
         data.bindVertexBuffers = std::move(rhs.data.bindVertexBuffers);
@@ -330,6 +461,59 @@ struct Command
         data.viewportTest.enable = rhs.data.viewportTest.enable;
         break;
       }
+
+      case CommandType::SET_COLOR_MASK:
+      {
+        data.colorMask.enabled = rhs.data.colorMask.enabled;
+        break;
+      }
+      case CommandType::CLEAR_STENCIL_BUFFER:
+      {
+        break;
+      }
+      case CommandType::CLEAR_DEPTH_BUFFER:
+      {
+        break;
+      }
+      case CommandType::SET_STENCIL_TEST_ENABLE:
+      {
+        data.stencilTest.enabled = rhs.data.stencilTest.enabled;
+        break;
+      }
+      case CommandType::SET_STENCIL_WRITE_MASK:
+      {
+        data.stencilWriteMask.mask = rhs.data.stencilWriteMask.mask;
+        break;
+      }
+      case CommandType::SET_STENCIL_OP:
+      {
+        data.stencilOp.failOp      = rhs.data.stencilOp.failOp;
+        data.stencilOp.depthFailOp = rhs.data.stencilOp.depthFailOp;
+        data.stencilOp.passOp      = rhs.data.stencilOp.passOp;
+        break;
+      }
+      case CommandType::SET_STENCIL_FUNC:
+      {
+        data.stencilFunc.compareMask = rhs.data.stencilFunc.compareMask;
+        data.stencilFunc.compareOp   = rhs.data.stencilFunc.compareOp;
+        data.stencilFunc.reference   = rhs.data.stencilFunc.reference;
+        break;
+      }
+      case CommandType::SET_DEPTH_COMPARE_OP:
+      {
+        data.depth.compareOp = rhs.data.depth.compareOp;
+        break;
+      }
+      case CommandType::SET_DEPTH_TEST_ENABLE:
+      {
+        data.depth.testEnabled = rhs.data.depth.testEnabled;
+        break;
+      }
+      case CommandType::SET_DEPTH_WRITE_ENABLE:
+      {
+        data.depth.writeEnabled = rhs.data.depth.writeEnabled;
+        break;
+      }
     }
     type = rhs.type;
   }
@@ -398,6 +582,60 @@ struct Command
     {
       bool enable;
     } viewportTest;
+
+    struct BeginRenderPassDescriptor
+    {
+      Graphics::RenderPass*             renderPass;
+      Graphics::RenderTarget*           renderTarget;
+      Graphics::Rect2D                  renderArea;
+      std::vector<Graphics::ClearValue> clearValues;
+    } beginRenderPass;
+
+    struct
+    {
+      Graphics::SyncObject* syncObject;
+    } endRenderPass;
+
+    struct
+    {
+      std::vector<const TestGraphicsCommandBuffer*> buffers;
+    } executeCommandBuffers;
+
+    struct
+    {
+      Graphics::CompareOp compareOp;
+      bool                testEnabled;
+      bool                writeEnabled;
+    } depth;
+
+    struct
+    {
+      Graphics::StencilOp failOp;
+      Graphics::StencilOp passOp;
+      Graphics::StencilOp depthFailOp;
+    } stencilOp;
+
+    struct
+    {
+      uint32_t mask;
+    } stencilWriteMask;
+
+    struct
+    {
+      uint32_t            compareMask;
+      Graphics::CompareOp compareOp;
+      uint32_t            reference;
+    } stencilFunc;
+
+    struct
+    {
+      bool enabled;
+    } stencilTest;
+
+    struct
+    {
+      bool enabled;
+    } colorMask;
   } data;
 };
 
@@ -509,12 +747,23 @@ public:
   }
 
   void BeginRenderPass(
-    Graphics::RenderPass&             renderPass,
-    Graphics::RenderTarget&           renderTarget,
-    Graphics::Extent2D                renderArea,
+    Graphics::RenderPass*             renderPass,
+    Graphics::RenderTarget*           renderTarget,
+    Graphics::Rect2D                  renderArea,
     std::vector<Graphics::ClearValue> clearValues) override
   {
-    mCallStack.PushCall("BeginRenderPass", "");
+    mCommands.emplace_back(CommandType::BEGIN_RENDER_PASS);
+    auto& cmd                             = mCommands.back();
+    cmd.data.beginRenderPass.renderPass   = renderPass;
+    cmd.data.beginRenderPass.renderTarget = renderTarget;
+    cmd.data.beginRenderPass.renderArea   = renderArea;
+    cmd.data.beginRenderPass.clearValues  = clearValues;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["renderPass"] << std::hex << renderPass;
+    namedParams["renderTarget"] << std::hex << renderTarget;
+    namedParams["renderArea"] << renderArea.width << ", " << renderArea.height;
+    mCallStack.PushCall("BeginRenderPass", namedParams.str(), namedParams);
   }
 
   /**
@@ -526,9 +775,29 @@ public:
    * dependencies (for example, to know when target texture is ready
    * before passing it to another render pass).
    */
-  void EndRenderPass() override
+  void EndRenderPass(Graphics::SyncObject* syncObject) override
   {
-    mCallStack.PushCall("EndRenderPass", "");
+    mCommands.emplace_back(CommandType::END_RENDER_PASS);
+    auto& cmd = mCommands.back();
+
+    cmd.data.endRenderPass.syncObject = syncObject;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["syncObject"] << std::hex << syncObject;
+    mCallStack.PushCall("EndRenderPass", namedParams.str(), namedParams);
+  }
+
+  void ExecuteCommandBuffers(std::vector<const CommandBuffer*>&& commandBuffers) override
+  {
+    mCommands.emplace_back();
+    auto& cmd = mCommands.back();
+    cmd.type  = CommandType::EXECUTE_COMMAND_BUFFERS;
+    cmd.data.executeCommandBuffers.buffers.reserve(commandBuffers.size());
+    for(auto&& item : commandBuffers)
+    {
+      cmd.data.executeCommandBuffers.buffers.emplace_back(static_cast<const TestGraphicsCommandBuffer*>(item));
+    }
+    mCallStack.PushCall("ExecuteCommandBuffers", "");
   }
 
   void Draw(
@@ -642,6 +911,112 @@ public:
     mCommands.back().data.viewportTest.enable = value;
   }
 
+  void SetColorMask(bool enabled) override
+  {
+    TraceCallStack::NamedParams params;
+    params["enabled"] << (enabled ? "T" : "F");
+    mCallStack.PushCall("SetColorMask", params.str(), params);
+    mCommands.emplace_back();
+    mCommands.back().type                   = CommandType::SET_COLOR_MASK;
+    mCommands.back().data.colorMask.enabled = enabled;
+  }
+
+  void ClearStencilBuffer() override
+  {
+    mCallStack.PushCall("SetStencilMask", "");
+    mCommands.emplace_back();
+    mCommands.back().type = CommandType::CLEAR_STENCIL_BUFFER;
+  }
+
+  void SetStencilTestEnable(bool stencilEnable) override
+  {
+    TraceCallStack::NamedParams params;
+    params["enabled"] << (stencilEnable ? "T" : "F");
+    mCallStack.PushCall("SetStencilTestEnable", params.str(), params);
+    mCommands.emplace_back();
+    mCommands.back().type                     = CommandType::SET_STENCIL_TEST_ENABLE;
+    mCommands.back().data.stencilTest.enabled = stencilEnable;
+  }
+
+  void SetStencilWriteMask(uint32_t writeMask) override
+  {
+    TraceCallStack::NamedParams params;
+    params["writeMask"] << std::hex << writeMask;
+    mCallStack.PushCall("SetStencilWriteMask", params.str(), params);
+    mCommands.emplace_back();
+    mCommands.back().type                       = CommandType::SET_STENCIL_WRITE_MASK;
+    mCommands.back().data.stencilWriteMask.mask = writeMask;
+  }
+
+  void SetStencilOp(Graphics::StencilOp failOp,
+                    Graphics::StencilOp passOp,
+                    Graphics::StencilOp depthFailOp) override
+  {
+    TraceCallStack::NamedParams params;
+    params["failOp"] << failOp;
+    params["passOp"] << passOp;
+    params["depthFailOp"] << depthFailOp;
+    mCallStack.PushCall("SetStencilOp", params.str(), params);
+    mCommands.emplace_back();
+    mCommands.back().type                       = CommandType::SET_STENCIL_OP;
+    mCommands.back().data.stencilOp.failOp      = failOp;
+    mCommands.back().data.stencilOp.passOp      = passOp;
+    mCommands.back().data.stencilOp.depthFailOp = depthFailOp;
+  }
+
+  void SetStencilFunc(Graphics::CompareOp compareOp,
+                      uint32_t            reference,
+                      uint32_t            compareMask) override
+  {
+    TraceCallStack::NamedParams params;
+    params["compareOp"] << compareOp;
+    params["compareMask"] << std::hex << compareMask;
+    params["reference"] << std::hex << reference;
+    mCallStack.PushCall("SetStencilFunc", params.str(), params);
+
+    mCommands.emplace_back();
+    mCommands.back().type = CommandType::SET_STENCIL_FUNC;
+
+    mCommands.back().data.stencilFunc.compareOp   = compareOp;
+    mCommands.back().data.stencilFunc.compareMask = compareMask;
+    mCommands.back().data.stencilFunc.reference   = reference;
+  }
+
+  void SetDepthCompareOp(Graphics::CompareOp compareOp) override
+  {
+    TraceCallStack::NamedParams params;
+    params["compareOp"] << compareOp;
+    mCallStack.PushCall("SetDepthCompareOp", params.str(), params);
+    mCommands.emplace_back();
+    mCommands.back().type                 = CommandType::SET_DEPTH_COMPARE_OP;
+    mCommands.back().data.depth.compareOp = compareOp;
+  }
+
+  void SetDepthTestEnable(bool depthTestEnable) override
+  {
+    TraceCallStack::NamedParams params;
+    params["enabled"] << (depthTestEnable ? "T" : "F");
+    mCallStack.PushCall("SetDepthTestEnable", params.str(), params);
+    mCommands.emplace_back();
+    mCommands.back().type                   = CommandType::SET_DEPTH_TEST_ENABLE;
+    mCommands.back().data.depth.testEnabled = depthTestEnable;
+  }
+  void SetDepthWriteEnable(bool depthWriteEnable) override
+  {
+    TraceCallStack::NamedParams params;
+    params["enabled"] << (depthWriteEnable ? "T" : "F");
+    mCallStack.PushCall("SetDepthWriteEnable", params.str(), params);
+    mCommands.emplace_back();
+    mCommands.back().type                    = CommandType::SET_DEPTH_WRITE_ENABLE;
+    mCommands.back().data.depth.writeEnabled = depthWriteEnable;
+  }
+  void ClearDepthBuffer() override
+  {
+    mCallStack.PushCall("ClearDepthBuffer", "");
+    mCommands.emplace_back();
+    mCommands.back().type = CommandType::CLEAR_DEPTH_BUFFER;
+  }
+
   [[nodiscard]] const std::vector<Command>& GetCommands() const
   {
     return mCommands;
@@ -662,7 +1037,9 @@ public:
   /**
    * Retrieves commands of specified type
    */
-  std::vector<Command*> GetCommandsByType(CommandTypeMask mask);
+  std::vector<const Command*> GetCommandsByType(CommandTypeMask mask) const;
+
+  std::vector<const Command*> GetChildCommandsByType(CommandTypeMask mask) const;
 
 private:
   TraceCallStack&    mCallStack;
index 51f0721..0886719 100644 (file)
 
 #include "test-graphics-buffer.h"
 #include "test-graphics-command-buffer.h"
+#include "test-graphics-framebuffer.h"
 #include "test-graphics-reflection.h"
+#include "test-graphics-render-pass.h"
+#include "test-graphics-render-target.h"
 #include "test-graphics-sampler.h"
 #include "test-graphics-shader.h"
+#include "test-graphics-sync-object.h"
 #include "test-graphics-texture.h"
 
 #include <dali/integration-api/gl-defines.h>
 
 namespace Dali
 {
-template<typename T>
-T* Uncast(const Graphics::CommandBuffer* object)
-{
-  return const_cast<T*>(static_cast<const T*>(object));
-}
-
-template<typename T>
-T* Uncast(const Graphics::Texture* object)
-{
-  return const_cast<T*>(static_cast<const T*>(object));
-}
-
-template<typename T>
-T* Uncast(const Graphics::Sampler* object)
-{
-  return const_cast<T*>(static_cast<const T*>(object));
-}
-
-template<typename T>
-T* Uncast(const Graphics::Buffer* object)
-{
-  return const_cast<T*>(static_cast<const T*>(object));
-}
-
-template<typename T>
-T* Uncast(const Graphics::Shader* object)
-{
-  return const_cast<T*>(static_cast<const T*>(object));
-}
-
 std::ostream& operator<<(std::ostream& o, const Graphics::BufferCreateInfo& bufferCreateInfo)
 {
   return o << "usage:" << std::hex << bufferCreateInfo.usage << ", size:" << std::dec << bufferCreateInfo.size;
@@ -173,70 +147,34 @@ std::ostream& operator<<(std::ostream& o, const Graphics::SamplerCreateInfo& cre
   return o;
 }
 
-class TestGraphicsMemory : public Graphics::Memory
+std::ostream& operator<<(std::ostream& o, const Graphics::ColorAttachment& colorAttachment)
 {
-public:
-  TestGraphicsMemory(TraceCallStack& callStack, TestGraphicsBuffer& buffer, uint32_t mappedOffset, uint32_t mappedSize)
-  : mCallStack(callStack),
-    mBuffer(buffer),
-    mMappedOffset(mappedOffset),
-    mMappedSize(mappedSize),
-    mLockedOffset(0u),
-    mLockedSize(0u)
-  {
-  }
-
-  void* LockRegion(uint32_t offset, uint32_t size) override
-  {
-    std::ostringstream o;
-    o << offset << ", " << size;
-    mCallStack.PushCall("Memory::LockRegion", o.str());
-
-    if(offset > mMappedOffset + mMappedSize ||
-       size + offset > mMappedOffset + mMappedSize)
-    {
-      fprintf(stderr, "TestGraphics.Memory::LockRegion() Out of bounds");
-      mBuffer.memory.resize(mMappedOffset + offset + size); // Grow to prevent memcpy from crashing
-    }
-    mLockedOffset = offset;
-    mLockedSize   = size;
-    return &mBuffer.memory[mMappedOffset + offset];
-  }
+  o << "attachmentId:" << colorAttachment.attachmentId
+    << " layerId:" << colorAttachment.layerId
+    << " levelId:" << colorAttachment.levelId
+    << " texture:" << colorAttachment.texture;
+  return o;
+}
 
-  void Unlock(bool flush) override
-  {
-    mCallStack.PushCall("Memory::Unlock", (flush ? "Flush" : "NoFlush"));
-    if(flush)
-    {
-      Flush();
-    }
-  }
+std::ostream& operator<<(std::ostream& o, const Graphics::DepthStencilAttachment& depthStencilAttachment)
+{
+  o << "depthTexture:" << depthStencilAttachment.depthTexture
+    << "depthLevel:" << depthStencilAttachment.depthLevel
+    << "stencilTexture:" << depthStencilAttachment.stencilTexture
+    << "stencilLevel:" << depthStencilAttachment.stencilLevel;
+  return o;
+}
 
-  void Flush() override
+std::ostream& operator<<(std::ostream& o, const Graphics::FramebufferCreateInfo& createInfo)
+{
+  o << "colorAttachments:";
+  for(auto i = 0u; i < createInfo.colorAttachments.size(); ++i)
   {
-    mCallStack.PushCall("Memory::Flush", "");
-    mBuffer.Bind();
-    mBuffer.Upload(mMappedOffset + mLockedOffset, mLockedSize);
-    mBuffer.Unbind();
+    o << "[" << i << "]=" << createInfo.colorAttachments[i] << "  ";
   }
-
-  TraceCallStack&     mCallStack;
-  TestGraphicsBuffer& mBuffer;
-  uint32_t            mMappedOffset;
-  uint32_t            mMappedSize;
-  uint32_t            mLockedOffset;
-  uint32_t            mLockedSize;
-};
-
-TestGraphicsController::TestGraphicsController()
-: mCallStack(true, "TestGraphicsController."),
-  mCommandBufferCallStack(true, "TestCommandBuffer.")
-{
-  mCallStack.Enable(true);
-  mCommandBufferCallStack.Enable(true);
-  auto& trace = mGl.GetTextureTrace();
-  trace.Enable(true);
-  trace.EnableLogging(true);
+  o << "depthStencilAttachment:" << createInfo.depthStencilAttachment;
+  o << "size: " << createInfo.size;
+  return o;
 }
 
 int GetNumComponents(Graphics::VertexInputFormat vertexFormat)
@@ -447,6 +385,143 @@ GLenum GetBlendOp(Graphics::BlendOp blendOp)
   return op;
 }
 
+struct GLCompareOp
+{
+  constexpr explicit GLCompareOp(Graphics::CompareOp compareOp)
+  {
+    switch(compareOp)
+    {
+      case Graphics::CompareOp::NEVER:
+        op = GL_NEVER;
+        break;
+      case Graphics::CompareOp::LESS:
+        op = GL_LESS;
+        break;
+      case Graphics::CompareOp::EQUAL:
+        op = GL_EQUAL;
+        break;
+      case Graphics::CompareOp::LESS_OR_EQUAL:
+        op = GL_LEQUAL;
+        break;
+      case Graphics::CompareOp::GREATER:
+        op = GL_GREATER;
+        break;
+      case Graphics::CompareOp::NOT_EQUAL:
+        op = GL_NOTEQUAL;
+        break;
+      case Graphics::CompareOp::GREATER_OR_EQUAL:
+        op = GL_GEQUAL;
+        break;
+      case Graphics::CompareOp::ALWAYS:
+        op = GL_ALWAYS;
+        break;
+    }
+  }
+  GLenum op{GL_LESS};
+};
+
+struct GLStencilOp
+{
+  constexpr explicit GLStencilOp(Graphics::StencilOp stencilOp)
+  {
+    switch(stencilOp)
+    {
+      case Graphics::StencilOp::KEEP:
+        op = GL_KEEP;
+        break;
+      case Graphics::StencilOp::ZERO:
+        op = GL_ZERO;
+        break;
+      case Graphics::StencilOp::REPLACE:
+        op = GL_REPLACE;
+        break;
+      case Graphics::StencilOp::INCREMENT_AND_CLAMP:
+        op = GL_INCR;
+        break;
+      case Graphics::StencilOp::DECREMENT_AND_CLAMP:
+        op = GL_DECR;
+        break;
+      case Graphics::StencilOp::INVERT:
+        op = GL_INVERT;
+        break;
+      case Graphics::StencilOp::INCREMENT_AND_WRAP:
+        op = GL_INCR_WRAP;
+        break;
+      case Graphics::StencilOp::DECREMENT_AND_WRAP:
+        op = GL_DECR_WRAP;
+        break;
+    }
+  }
+  GLenum op{GL_KEEP};
+};
+
+class TestGraphicsMemory : public Graphics::Memory
+{
+public:
+  TestGraphicsMemory(TraceCallStack& callStack, TestGraphicsBuffer& buffer, uint32_t mappedOffset, uint32_t mappedSize)
+  : mCallStack(callStack),
+    mBuffer(buffer),
+    mMappedOffset(mappedOffset),
+    mMappedSize(mappedSize),
+    mLockedOffset(0u),
+    mLockedSize(0u)
+  {
+  }
+
+  void* LockRegion(uint32_t offset, uint32_t size) override
+  {
+    std::ostringstream o;
+    o << offset << ", " << size;
+    mCallStack.PushCall("Memory::LockRegion", o.str());
+
+    if(offset > mMappedOffset + mMappedSize ||
+       size + offset > mMappedOffset + mMappedSize)
+    {
+      fprintf(stderr, "TestGraphics.Memory::LockRegion() Out of bounds");
+      mBuffer.memory.resize(mMappedOffset + offset + size); // Grow to prevent memcpy from crashing
+    }
+    mLockedOffset = offset;
+    mLockedSize   = size;
+    return &mBuffer.memory[mMappedOffset + offset];
+  }
+
+  void Unlock(bool flush) override
+  {
+    mCallStack.PushCall("Memory::Unlock", (flush ? "Flush" : "NoFlush"));
+    if(flush)
+    {
+      Flush();
+    }
+  }
+
+  void Flush() override
+  {
+    mCallStack.PushCall("Memory::Flush", "");
+    mBuffer.Bind();
+    mBuffer.Upload(mMappedOffset + mLockedOffset, mLockedSize);
+    mBuffer.Unbind();
+  }
+
+  TraceCallStack&     mCallStack;
+  TestGraphicsBuffer& mBuffer;
+  uint32_t            mMappedOffset;
+  uint32_t            mMappedSize;
+  uint32_t            mLockedOffset;
+  uint32_t            mLockedSize;
+};
+
+TestGraphicsController::TestGraphicsController()
+: mCallStack(true, "TestGraphicsController."),
+  mCommandBufferCallStack(true, "TestCommandBuffer."),
+  mFrameBufferCallStack(true, "TestFrameBuffer.")
+{
+  mCallStack.Enable(true);
+  mCommandBufferCallStack.Enable(true);
+  auto& trace = mGl.GetTextureTrace();
+  trace.Enable(true);
+  trace.EnableLogging(true);
+}
+
 void TestGraphicsController::SubmitCommandBuffers(const Graphics::SubmitInfo& submitInfo)
 {
   TraceCallStack::NamedParams namedParams;
@@ -460,193 +535,420 @@ void TestGraphicsController::SubmitCommandBuffers(const Graphics::SubmitInfo& su
   for(auto& graphicsCommandBuffer : submitInfo.cmdBuffer)
   {
     auto commandBuffer = Uncast<TestGraphicsCommandBuffer>(graphicsCommandBuffer);
+    ProcessCommandBuffer(*commandBuffer);
+  }
+}
+
+void TestGraphicsController::ProcessCommandBuffer(TestGraphicsCommandBuffer& commandBuffer)
+{
+  bool                     scissorEnabled = false;
+  TestGraphicsFramebuffer* currentFramebuffer{nullptr};
+  TestGraphicsPipeline*    currentPipeline{nullptr};
 
-    auto value = commandBuffer->GetCommandsByType(0 | CommandType::BIND_TEXTURES);
-    if(!value.empty())
+  for(auto& cmd : commandBuffer.GetCommands())
+  {
+    // process command
+    switch(cmd.type)
     {
-      // must be fixed
-      for(auto& binding : value[0]->data.bindTextures.textureBindings)
+      case CommandType::FLUSH:
       {
-        if(binding.texture)
+        // Nothing to do here
+        break;
+      }
+      case CommandType::BIND_TEXTURES:
+      {
+        for(auto& binding : cmd.data.bindTextures.textureBindings)
         {
-          auto texture = Uncast<TestGraphicsTexture>(binding.texture);
-
-          texture->Bind(binding.binding);
-
-          if(binding.sampler)
+          if(binding.texture)
           {
-            auto sampler = Uncast<TestGraphicsSampler>(binding.sampler);
-            if(sampler)
+            auto texture = Uncast<TestGraphicsTexture>(binding.texture);
+            texture->Bind(binding.binding);
+
+            if(binding.sampler)
             {
-              sampler->Apply(texture->GetTarget());
+              auto sampler = Uncast<TestGraphicsSampler>(binding.sampler);
+              if(sampler)
+              {
+                sampler->Apply(texture->GetTarget());
+              }
             }
-          }
 
-          texture->Prepare(); // Ensure native texture is ready
+            texture->Prepare(); // Ensure native texture is ready
+          }
         }
+        break;
       }
-    }
-
-    // IndexBuffer binding,
-    auto bindIndexBufferCmds = commandBuffer->GetCommandsByType(0 | CommandType::BIND_INDEX_BUFFER);
-    if(!bindIndexBufferCmds.empty())
-    {
-      auto& indexBufferBinding = bindIndexBufferCmds[0]->data.bindIndexBuffer;
-      if(indexBufferBinding.buffer)
+      case CommandType::BIND_VERTEX_BUFFERS:
       {
-        auto buffer = Uncast<TestGraphicsBuffer>(indexBufferBinding.buffer);
-        buffer->Bind();
+        for(auto& binding : cmd.data.bindVertexBuffers.vertexBufferBindings)
+        {
+          auto graphicsBuffer = binding.buffer;
+          auto vertexBuffer   = Uncast<TestGraphicsBuffer>(graphicsBuffer);
+          vertexBuffer->Bind();
+        }
+        break;
       }
-    }
-
-    // VertexBuffer binding,
-    auto bindVertexBufferCmds = commandBuffer->GetCommandsByType(0 | CommandType::BIND_VERTEX_BUFFERS);
-    if(!bindVertexBufferCmds.empty())
-    {
-      for(auto& binding : bindVertexBufferCmds[0]->data.bindVertexBuffers.vertexBufferBindings)
+      case CommandType::BIND_INDEX_BUFFER:
       {
-        auto graphicsBuffer = binding.buffer;
-        auto vertexBuffer   = Uncast<TestGraphicsBuffer>(graphicsBuffer);
-        vertexBuffer->Bind();
+        auto& indexBufferBinding = cmd.data.bindIndexBuffer;
+        if(indexBufferBinding.buffer)
+        {
+          auto buffer = Uncast<TestGraphicsBuffer>(indexBufferBinding.buffer);
+          buffer->Bind();
+        }
+        break;
       }
-    }
-
-    bool scissorEnabled = false;
+      case CommandType::BIND_UNIFORM_BUFFER:
+      {
+        if(currentPipeline)
+        {
+          auto& bindings = cmd.data.bindUniformBuffers;
+          auto  buffer   = bindings.standaloneUniformsBufferBinding;
 
-    auto scissorTestList = commandBuffer->GetCommandsByType(0 | CommandType::SET_SCISSOR_TEST);
-    if(!scissorTestList.empty())
-    {
-      if(scissorTestList[0]->data.scissorTest.enable)
+          // based on reflection, issue gl calls
+          buffer.buffer->BindAsUniformBuffer(static_cast<const TestGraphicsProgram*>(currentPipeline->programState.program), bindings.standaloneUniformsBufferBinding);
+        }
+        break;
+      }
+      case CommandType::BIND_SAMPLERS:
       {
-        mGl.Enable(GL_SCISSOR_TEST);
-        scissorEnabled = true;
+        break;
       }
-      else
+      case CommandType::BIND_PIPELINE:
       {
-        mGl.Disable(GL_SCISSOR_TEST);
+        currentPipeline = Uncast<TestGraphicsPipeline>(cmd.data.bindPipeline.pipeline);
+        BindPipeline(currentPipeline);
+        break;
+      }
+      case CommandType::DRAW:
+      {
+        if(currentPipeline)
+        {
+          mGl.DrawArrays(GetTopology(currentPipeline->inputAssemblyState.topology),
+                         0,
+                         cmd.data.draw.draw.vertexCount);
+        }
+        break;
+      }
+      case CommandType::DRAW_INDEXED:
+      {
+        if(currentPipeline)
+        {
+          mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology),
+                           static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
+                           GL_UNSIGNED_SHORT,
+                           reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex));
+        }
+        break;
+      }
+      case CommandType::DRAW_INDEXED_INDIRECT:
+      {
+        if(currentPipeline)
+        {
+          mGl.DrawElements(GetTopology(currentPipeline->inputAssemblyState.topology),
+                           static_cast<GLsizei>(cmd.data.draw.drawIndexed.indexCount),
+                           GL_UNSIGNED_SHORT,
+                           reinterpret_cast<void*>(cmd.data.draw.drawIndexed.firstIndex));
+        }
+        break;
+      }
+      case CommandType::SET_SCISSOR:
+      {
+        if(scissorEnabled)
+        {
+          auto& rect = cmd.data.scissor.region;
+          mGl.Scissor(rect.x, rect.y, rect.width, rect.height);
+        }
+        break;
+      }
+      case CommandType::SET_SCISSOR_TEST:
+      {
+        if(cmd.data.scissorTest.enable)
+        {
+          mGl.Enable(GL_SCISSOR_TEST);
+          scissorEnabled = true;
+        }
+        else
+        {
+          mGl.Disable(GL_SCISSOR_TEST);
+          scissorEnabled = false;
+        }
+        break;
+      }
+      case CommandType::SET_VIEWPORT_TEST:
+      {
+        break;
+      }
+      case CommandType::SET_VIEWPORT: // @todo Consider correcting for orientation here?
+      {
+        auto& rect = cmd.data.viewport.region;
+        mGl.Viewport(rect.x, rect.y, rect.width, rect.height);
+        break;
       }
-    }
-
-    auto scissorList = commandBuffer->GetCommandsByType(0 | CommandType::SET_SCISSOR);
-    if(!scissorList.empty() && scissorEnabled)
-    {
-      auto& rect = scissorList[0]->data.scissor.region;
-      mGl.Scissor(rect.x, rect.y, rect.width, rect.height);
-    }
 
-    auto viewportList = commandBuffer->GetCommandsByType(0 | CommandType::SET_VIEWPORT);
-    if(!viewportList.empty())
-    {
-      mGl.Viewport(viewportList[0]->data.viewport.region.x, viewportList[0]->data.viewport.region.y, viewportList[0]->data.viewport.region.width, viewportList[0]->data.viewport.region.height);
-    }
+      case CommandType::SET_COLOR_MASK:
+      {
+        // Set all channels to the same mask
+        const bool mask = cmd.data.colorMask.enabled;
+        mGl.ColorMask(mask, mask, mask, mask);
+        break;
+      }
+      case CommandType::CLEAR_STENCIL_BUFFER:
+      {
+        mGl.Clear(GL_STENCIL_BUFFER_BIT);
+        break;
+      }
+      case CommandType::CLEAR_DEPTH_BUFFER:
+      {
+        mGl.Clear(GL_DEPTH_BUFFER_BIT);
+        break;
+      }
 
-    // ignore viewport enable
+      case CommandType::SET_STENCIL_TEST_ENABLE:
+      {
+        if(cmd.data.stencilTest.enabled)
+        {
+          mGl.Enable(GL_STENCIL_TEST);
+        }
+        else
+        {
+          mGl.Disable(GL_STENCIL_TEST);
+        }
+        break;
+      }
 
-    // Pipeline attribute setup
-    auto bindPipelineCmds = commandBuffer->GetCommandsByType(0 | CommandType::BIND_PIPELINE);
-    if(!bindPipelineCmds.empty())
-    {
-      auto  pipeline = bindPipelineCmds[0]->data.bindPipeline.pipeline;
-      auto& vi       = pipeline->vertexInputState;
-      for(auto& attribute : vi.attributes)
+      case CommandType::SET_STENCIL_FUNC:
       {
-        mGl.EnableVertexAttribArray(attribute.location);
-        uint32_t attributeOffset = attribute.offset;
-        GLsizei  stride          = vi.bufferBindings[attribute.binding].stride;
-
-        mGl.VertexAttribPointer(attribute.location,
-                                GetNumComponents(attribute.format),
-                                GetGlType(attribute.format),
-                                GL_FALSE, // Not normalized
-                                stride,
-                                reinterpret_cast<void*>(attributeOffset));
+        mGl.StencilFunc(GLCompareOp(cmd.data.stencilFunc.compareOp).op,
+                        cmd.data.stencilFunc.reference,
+                        cmd.data.stencilFunc.compareMask);
+        break;
       }
 
-      // Cull face setup
-      auto& rasterizationState = pipeline->rasterizationState;
-      if(rasterizationState.cullMode == Graphics::CullMode::NONE)
+      case CommandType::SET_STENCIL_WRITE_MASK:
       {
-        mGl.Disable(GL_CULL_FACE);
+        mGl.StencilMask(cmd.data.stencilWriteMask.mask);
+        break;
       }
-      else
+      case CommandType::SET_STENCIL_OP:
       {
-        mGl.Enable(GL_CULL_FACE);
-        mGl.CullFace(GetCullFace(rasterizationState.cullMode));
+        mGl.StencilOp(GLStencilOp(cmd.data.stencilOp.failOp).op,
+                      GLStencilOp(cmd.data.stencilOp.depthFailOp).op,
+                      GLStencilOp(cmd.data.stencilOp.passOp).op);
+        break;
       }
 
-      mGl.FrontFace(GetFrontFace(rasterizationState.frontFace));
-      // We don't modify glPolygonMode in our context/abstraction from GL_FILL (the GL default),
-      // so it isn't present in the API (and won't have any tests!)
-
-      // Blending setup
-      auto& colorBlendState = pipeline->colorBlendState;
-      if(colorBlendState.blendEnable)
+      case CommandType::SET_DEPTH_COMPARE_OP:
       {
-        mGl.Enable(GL_BLEND);
-
-        mGl.BlendFuncSeparate(GetBlendFactor(colorBlendState.srcColorBlendFactor),
-                              GetBlendFactor(colorBlendState.dstColorBlendFactor),
-                              GetBlendFactor(colorBlendState.srcAlphaBlendFactor),
-                              GetBlendFactor(colorBlendState.dstAlphaBlendFactor));
-        if(colorBlendState.colorBlendOp != colorBlendState.alphaBlendOp)
+        mGl.DepthFunc(GLCompareOp(cmd.data.depth.compareOp).op);
+        break;
+      }
+      case CommandType::SET_DEPTH_TEST_ENABLE:
+      {
+        if(cmd.data.depth.testEnabled)
         {
-          mGl.BlendEquationSeparate(GetBlendOp(colorBlendState.colorBlendOp), GetBlendOp(colorBlendState.alphaBlendOp));
+          mGl.Enable(GL_DEPTH_TEST);
         }
         else
         {
-          mGl.BlendEquation(GetBlendOp(colorBlendState.colorBlendOp));
+          mGl.Disable(GL_DEPTH_TEST);
         }
-        mGl.BlendColor(colorBlendState.blendConstants[0],
-                       colorBlendState.blendConstants[1],
-                       colorBlendState.blendConstants[2],
-                       colorBlendState.blendConstants[3]);
+        break;
       }
-      else
+      case CommandType::SET_DEPTH_WRITE_ENABLE:
       {
-        mGl.Disable(GL_BLEND);
+        mGl.DepthMask(cmd.data.depth.writeEnabled);
+        break;
       }
 
-      // draw call
-      auto topology = pipeline->inputAssemblyState.topology;
-
-      // UniformBuffer binding (once we know pipeline)
-      auto bindUniformBuffersCmds = commandBuffer->GetCommandsByType(0 | CommandType::BIND_UNIFORM_BUFFER);
-      if(!bindUniformBuffersCmds.empty())
+      case CommandType::EXECUTE_COMMAND_BUFFERS:
       {
-        auto buffer = bindUniformBuffersCmds[0]->data.bindUniformBuffers.standaloneUniformsBufferBinding;
-
-        // based on reflection, issue gl calls
-        buffer.buffer->BindAsUniformBuffer(static_cast<const TestGraphicsProgram*>(pipeline->programState.program));
+        // Process secondary command buffers
+        for(auto& buf : cmd.data.executeCommandBuffers.buffers)
+        {
+          ProcessCommandBuffer(*Uncast<TestGraphicsCommandBuffer>(buf));
+        }
+        break;
       }
-
-      auto drawCmds = commandBuffer->GetCommandsByType(0 |
-                                                       CommandType::DRAW |
-                                                       CommandType::DRAW_INDEXED_INDIRECT |
-                                                       CommandType::DRAW_INDEXED);
-
-      if(!drawCmds.empty())
+      case CommandType::BEGIN_RENDER_PASS:
       {
-        if(drawCmds[0]->data.draw.type == DrawCallDescriptor::Type::DRAW_INDEXED)
+        auto renderTarget = Uncast<TestGraphicsRenderTarget>(cmd.data.beginRenderPass.renderTarget);
+
+        if(renderTarget)
         {
-          mGl.DrawElements(GetTopology(topology),
-                           static_cast<GLsizei>(drawCmds[0]->data.draw.drawIndexed.indexCount),
-                           GL_UNSIGNED_SHORT,
-                           reinterpret_cast<void*>(drawCmds[0]->data.draw.drawIndexed.firstIndex));
+          auto fb = renderTarget->mCreateInfo.framebuffer;
+          if(fb)
+          {
+            if(currentFramebuffer != fb)
+            {
+              currentFramebuffer = Uncast<TestGraphicsFramebuffer>(fb);
+              currentFramebuffer->Bind();
+            }
+          }
+          else
+          {
+            mGl.BindFramebuffer(GL_FRAMEBUFFER, 0);
+          }
         }
         else
         {
-          mGl.DrawArrays(GetTopology(topology), 0, drawCmds[0]->data.draw.draw.vertexCount);
+          mGl.BindFramebuffer(GL_FRAMEBUFFER, 0);
         }
+
+        auto& clearValues = cmd.data.beginRenderPass.clearValues;
+        if(clearValues.size() > 0)
+        {
+          const auto renderPass = static_cast<TestGraphicsRenderPass*>(cmd.data.beginRenderPass.renderPass);
+          if(renderPass)
+          {
+            const auto& color0 = renderPass->attachments[0];
+            GLuint      mask   = 0;
+            if(color0.loadOp == Graphics::AttachmentLoadOp::CLEAR)
+            {
+              mask |= GL_COLOR_BUFFER_BIT;
+
+              // Set clear color (todo: cache it!)
+              // Something goes wrong here if Alpha mask is GL_TRUE
+              mGl.ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
+              mGl.ClearColor(clearValues[0].color.r,
+                             clearValues[0].color.g,
+                             clearValues[0].color.b,
+                             clearValues[0].color.a);
+            }
+
+            // check for depth stencil
+            if(renderPass->attachments.size() > 1)
+            {
+              const auto& depthStencil = renderPass->attachments.back();
+              if(depthStencil.loadOp == Graphics::AttachmentLoadOp::CLEAR)
+              {
+                mGl.DepthMask(true);
+                uint32_t depthClearColor = 0u;
+                if(clearValues.size() == renderPass->attachments.size())
+                {
+                  depthClearColor = clearValues.back().depthStencil.depth;
+                }
+                mGl.ClearDepthf(depthClearColor);
+                mask |= GL_DEPTH_BUFFER_BIT;
+              }
+              if(depthStencil.stencilLoadOp == Graphics::AttachmentLoadOp::CLEAR)
+              {
+                uint32_t stencilClearColor = 0u;
+                if(clearValues.size() == renderPass->attachments.size())
+                {
+                  stencilClearColor = clearValues.back().depthStencil.stencil;
+                }
+                mGl.ClearStencil(stencilClearColor);
+                mGl.StencilMask(0xFF); // Clear all the bitplanes (assume 8)
+                mask |= GL_STENCIL_BUFFER_BIT;
+              }
+            }
+
+            if(mask != 0)
+            {
+              // Test scissor area and RT size
+              const auto& area = cmd.data.beginRenderPass.renderArea;
+              if(area.x == 0 &&
+                 area.y == 0 &&
+                 renderTarget &&
+                 area.width == renderTarget->mCreateInfo.extent.width &&
+                 area.height == renderTarget->mCreateInfo.extent.height)
+              {
+                mGl.Disable(GL_SCISSOR_TEST);
+                mGl.Clear(mask);
+              }
+              else
+              {
+                mGl.Enable(GL_SCISSOR_TEST);
+                mGl.Scissor(cmd.data.beginRenderPass.renderArea.x, cmd.data.beginRenderPass.renderArea.y, cmd.data.beginRenderPass.renderArea.width, cmd.data.beginRenderPass.renderArea.height);
+                mGl.Clear(mask);
+                mGl.Disable(GL_SCISSOR_TEST);
+              }
+            }
+          }
+          else
+          {
+            DALI_ASSERT_DEBUG(0 && "BeginRenderPass has no render pass");
+          }
+        }
+        break;
       }
-      // attribute clear
-      for(auto& attribute : vi.attributes)
+      case CommandType::END_RENDER_PASS:
       {
-        mGl.DisableVertexAttribArray(attribute.location);
+        if(cmd.data.endRenderPass.syncObject != nullptr)
+        {
+          auto syncObject = Uncast<TestGraphicsSyncObject>(cmd.data.endRenderPass.syncObject);
+          syncObject->InitializeResource(); // create the sync object.
+        }
+        break;
       }
     }
   }
 }
 
+void TestGraphicsController::BindPipeline(TestGraphicsPipeline* pipeline)
+{
+  auto& vi = pipeline->vertexInputState;
+  for(auto& attribute : vi.attributes)
+  {
+    mGl.EnableVertexAttribArray(attribute.location);
+    uint32_t attributeOffset = attribute.offset;
+    GLsizei  stride          = vi.bufferBindings[attribute.binding].stride;
+
+    mGl.VertexAttribPointer(attribute.location,
+                            GetNumComponents(attribute.format),
+                            GetGlType(attribute.format),
+                            GL_FALSE, // Not normalized
+                            stride,
+                            reinterpret_cast<void*>(attributeOffset));
+  }
+
+  // Cull face setup
+  auto& rasterizationState = pipeline->rasterizationState;
+  if(rasterizationState.cullMode == Graphics::CullMode::NONE)
+  {
+    mGl.Disable(GL_CULL_FACE);
+  }
+  else
+  {
+    mGl.Enable(GL_CULL_FACE);
+    mGl.CullFace(GetCullFace(rasterizationState.cullMode));
+  }
+
+  mGl.FrontFace(GetFrontFace(rasterizationState.frontFace));
+
+  // Blending setup
+  auto& colorBlendState = pipeline->colorBlendState;
+  if(colorBlendState.blendEnable)
+  {
+    mGl.Enable(GL_BLEND);
+
+    mGl.BlendFuncSeparate(GetBlendFactor(colorBlendState.srcColorBlendFactor),
+                          GetBlendFactor(colorBlendState.dstColorBlendFactor),
+                          GetBlendFactor(colorBlendState.srcAlphaBlendFactor),
+                          GetBlendFactor(colorBlendState.dstAlphaBlendFactor));
+    if(colorBlendState.colorBlendOp != colorBlendState.alphaBlendOp)
+    {
+      mGl.BlendEquationSeparate(GetBlendOp(colorBlendState.colorBlendOp), GetBlendOp(colorBlendState.alphaBlendOp));
+    }
+    else
+    {
+      mGl.BlendEquation(GetBlendOp(colorBlendState.colorBlendOp));
+    }
+    mGl.BlendColor(colorBlendState.blendConstants[0],
+                   colorBlendState.blendConstants[1],
+                   colorBlendState.blendConstants[2],
+                   colorBlendState.blendConstants[3]);
+  }
+  else
+  {
+    mGl.Disable(GL_BLEND);
+  }
+
+  auto* program = static_cast<const TestGraphicsProgram*>(pipeline->programState.program);
+  mGl.UseProgram(program->mImpl->mId);
+}
+
 /**
  * @brief Presents render target
  * @param renderTarget render target to present
@@ -713,6 +1015,15 @@ void TestGraphicsController::UpdateTextures(const std::vector<Graphics::TextureU
   }
 }
 
+void TestGraphicsController::GenerateTextureMipmaps(const Graphics::Texture& texture)
+{
+  mCallStack.PushCall("GenerateTextureMipmaps", "");
+
+  auto gfxTexture = Uncast<TestGraphicsTexture>(&texture);
+  mGl.BindTexture(gfxTexture->GetTarget(), 0);
+  mGl.GenerateMipmap(gfxTexture->GetTarget());
+}
+
 bool TestGraphicsController::EnableDepthStencilBuffer(bool enableDepth, bool enableStencil)
 {
   TraceCallStack::NamedParams namedParams;
@@ -770,7 +1081,7 @@ Graphics::UniquePtr<Graphics::CommandBuffer> TestGraphicsController::CreateComma
 Graphics::UniquePtr<Graphics::RenderPass> TestGraphicsController::CreateRenderPass(const Graphics::RenderPassCreateInfo& renderPassCreateInfo, Graphics::UniquePtr<Graphics::RenderPass>&& oldRenderPass)
 {
   mCallStack.PushCall("CreateRenderPass", "");
-  return nullptr;
+  return Graphics::MakeUnique<TestGraphicsRenderPass>(mGl, renderPassCreateInfo);
 }
 
 Graphics::UniquePtr<Graphics::Texture> TestGraphicsController::CreateTexture(const Graphics::TextureCreateInfo& textureCreateInfo, Graphics::UniquePtr<Graphics::Texture>&& oldTexture)
@@ -782,10 +1093,15 @@ Graphics::UniquePtr<Graphics::Texture> TestGraphicsController::CreateTexture(con
   return Graphics::MakeUnique<TestGraphicsTexture>(mGl, textureCreateInfo);
 }
 
-Graphics::UniquePtr<Graphics::Framebuffer> TestGraphicsController::CreateFramebuffer(const Graphics::FramebufferCreateInfo& framebufferCreateInfo, Graphics::UniquePtr<Graphics::Framebuffer>&& oldFramebuffer)
+Graphics::UniquePtr<Graphics::Framebuffer> TestGraphicsController::CreateFramebuffer(
+  const Graphics::FramebufferCreateInfo&       createInfo,
+  Graphics::UniquePtr<Graphics::Framebuffer>&& oldFramebuffer)
 {
-  mCallStack.PushCall("CreateFramebuffer", "");
-  return nullptr;
+  TraceCallStack::NamedParams namedParams;
+  namedParams["framebufferCreateInfo"] << createInfo;
+  mCallStack.PushCall("Controller::CreateFramebuffer", namedParams.str(), namedParams);
+
+  return Graphics::MakeUnique<TestGraphicsFramebuffer>(mFrameBufferCallStack, mGl, createInfo);
 }
 
 Graphics::UniquePtr<Graphics::Pipeline> TestGraphicsController::CreatePipeline(const Graphics::PipelineCreateInfo& pipelineCreateInfo, Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
@@ -849,7 +1165,15 @@ Graphics::UniquePtr<Graphics::Sampler> TestGraphicsController::CreateSampler(con
 Graphics::UniquePtr<Graphics::RenderTarget> TestGraphicsController::CreateRenderTarget(const Graphics::RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<Graphics::RenderTarget>&& oldRenderTarget)
 {
   mCallStack.PushCall("CreateRenderTarget", "");
-  return nullptr;
+  return Graphics::MakeUnique<TestGraphicsRenderTarget>(mGl, renderTargetCreateInfo);
+}
+
+Graphics::UniquePtr<Graphics::SyncObject> TestGraphicsController::CreateSyncObject(
+  const Graphics::SyncObjectCreateInfo&       syncObjectCreateInfo,
+  Graphics::UniquePtr<Graphics::SyncObject>&& oldSyncObject)
+{
+  mCallStack.PushCall("CreateSyncObject", "");
+  return Graphics::MakeUnique<TestGraphicsSyncObject>(mGraphicsSyncImpl, syncObjectCreateInfo);
 }
 
 Graphics::UniquePtr<Graphics::Memory> TestGraphicsController::MapBufferRange(const Graphics::MapBufferInfo& mapInfo)
index 803678e..cabc414 100644 (file)
 #include <dali/graphics-api/graphics-controller.h>
 #include "test-gl-abstraction.h"
 #include "test-gl-context-helper-abstraction.h"
-#include "test-gl-sync-abstraction.h"
+#include "test-graphics-command-buffer.h"
 #include "test-graphics-program.h"
 #include "test-graphics-reflection.h"
+#include "test-graphics-sync-impl.h"
 
 namespace Dali
 {
@@ -36,6 +37,60 @@ std::ostream& operator<<(std::ostream& o, Graphics::SamplerFilter filterMode);
 std::ostream& operator<<(std::ostream& o, Graphics::SamplerMipmapMode mipmapMode);
 std::ostream& operator<<(std::ostream& o, const Graphics::SamplerCreateInfo& createInfo);
 
+template<typename T>
+T* Uncast(const Graphics::CommandBuffer* object)
+{
+  return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::Texture* object)
+{
+  return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::Sampler* object)
+{
+  return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::Buffer* object)
+{
+  return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::Shader* object)
+{
+  return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::Framebuffer* object)
+{
+  return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::Pipeline* object)
+{
+  return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::RenderTarget* object)
+{
+  return const_cast<T*>(static_cast<const T*>(object));
+}
+
+template<typename T>
+T* Uncast(const Graphics::SyncObject* object)
+{
+  return const_cast<T*>(static_cast<const T*>(object));
+}
+
 class TestGraphicsController : public Dali::Graphics::Controller
 {
 public:
@@ -53,14 +108,14 @@ public:
     return mGl;
   }
 
-  Integration::GlSyncAbstraction& GetGlSyncAbstraction() override
+  Integration::GlContextHelperAbstraction& GetGlContextHelperAbstraction() override
   {
-    return mGlSyncAbstraction;
+    return mGlContextHelperAbstraction;
   }
 
-  Integration::GlContextHelperAbstraction& GetGlContextHelperAbstraction() override
+  TestGraphicsSyncImplementation& GetGraphicsSyncImpl()
   {
-    return mGlContextHelperAbstraction;
+    return mGraphicsSyncImpl;
   }
 
   void SubmitCommandBuffers(const Graphics::SubmitInfo& submitInfo) override;
@@ -113,6 +168,12 @@ public:
                       const std::vector<Graphics::TextureUpdateSourceInfo>& sourceList) override;
 
   /**
+   * Auto generates mipmaps for the texture
+   * @param[in] texture The texture
+   */
+  void GenerateTextureMipmaps(const Graphics::Texture& texture) override;
+
+  /**
    * TBD: do we need those functions in the new implementation?
    */
   bool EnableDepthStencilBuffer(bool enableDepth, bool enableStencil) override;
@@ -219,11 +280,20 @@ public:
   Graphics::UniquePtr<Graphics::RenderTarget> CreateRenderTarget(const Graphics::RenderTargetCreateInfo& renderTargetCreateInfo, Graphics::UniquePtr<Graphics::RenderTarget>&& oldRenderTarget) override;
 
   /**
+   * @brief Creates new sync object
+   * Could add timeout etc to createinfo... but nah.
+   *
+   * @return pointer to the SyncObject
+   */
+  Graphics::UniquePtr<Graphics::SyncObject> CreateSyncObject(const Graphics::SyncObjectCreateInfo&       syncObjectCreateInfo,
+                                                             Graphics::UniquePtr<Graphics::SyncObject>&& oldSyncObject) override;
+
+  /**
    * @brief Maps memory associated with Buffer object
    *
    * @param[in] mapInfo Filled details of mapped resource
    *
-   * @return Returns pointer to Memory object or Graphicsnullptr on error
+   * @return Returns pointer to Memory object or nullptr on error
    */
   Graphics::UniquePtr<Graphics::Memory> MapBufferRange(const Graphics::MapBufferInfo& mapInfo) override;
 
@@ -331,13 +401,18 @@ public: // Test Functions
    */
   bool GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData) override;
 
+  void ProcessCommandBuffer(TestGraphicsCommandBuffer& commandBuffer);
+
+  void BindPipeline(TestGraphicsPipeline* pipeline);
+
 public:
   mutable TraceCallStack                    mCallStack;
   mutable TraceCallStack                    mCommandBufferCallStack;
+  mutable TraceCallStack                    mFrameBufferCallStack;
   mutable std::vector<Graphics::SubmitInfo> mSubmitStack;
 
   TestGlAbstraction              mGl;
-  TestGlSyncAbstraction          mGlSyncAbstraction;
+  TestGraphicsSyncImplementation mGraphicsSyncImpl;
   TestGlContextHelperAbstraction mGlContextHelperAbstraction;
 
   bool isDiscardQueueEmptyResult{true};
@@ -352,6 +427,10 @@ public:
   };
   std::vector<ProgramCache> mProgramCache;
 
+  struct PipelineCache
+  {
+  };
+
   std::vector<UniformData> mCustomUniforms;
 };
 
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-framebuffer.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-framebuffer.cpp
new file mode 100644 (file)
index 0000000..74f1e29
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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-graphics-framebuffer.h"
+#include <dali/integration-api/gl-defines.h>
+#include "test-graphics-controller.h"
+#include "test-graphics-texture.h"
+
+namespace
+{
+const GLenum COLOR_ATTACHMENTS[] =
+  {
+    GL_COLOR_ATTACHMENT0,
+    GL_COLOR_ATTACHMENT1,
+    GL_COLOR_ATTACHMENT2,
+    GL_COLOR_ATTACHMENT3,
+    GL_COLOR_ATTACHMENT4,
+    GL_COLOR_ATTACHMENT5,
+    GL_COLOR_ATTACHMENT6,
+    GL_COLOR_ATTACHMENT7,
+};
+
+struct DEPTH_STENCIL_ATTACHMENT_TYPE
+{
+  constexpr explicit DEPTH_STENCIL_ATTACHMENT_TYPE(Graphics::Format textureFormat)
+  {
+    switch(textureFormat)
+    {
+      case Graphics::Format::D16_UNORM:
+      case Graphics::Format::D32_SFLOAT:
+      case Graphics::Format::X8_D24_UNORM_PACK32:
+      {
+        attachment = GL_DEPTH_ATTACHMENT;
+        break;
+      }
+
+      case Graphics::Format::S8_UINT:
+      {
+        attachment = GL_STENCIL_ATTACHMENT;
+        break;
+      }
+
+      case Graphics::Format::D16_UNORM_S8_UINT:
+      case Graphics::Format::D24_UNORM_S8_UINT:
+      case Graphics::Format::D32_SFLOAT_S8_UINT:
+      {
+        attachment = GL_DEPTH_STENCIL_ATTACHMENT;
+        break;
+      }
+      default:
+      {
+        attachment = GL_NONE;
+        break;
+      }
+    }
+  }
+  GLenum attachment{GL_NONE};
+};
+
+} // namespace
+//namespace
+
+namespace Dali
+{
+TestGraphicsFramebuffer::TestGraphicsFramebuffer(
+  TraceCallStack&                        callStack,
+  TestGlAbstraction&                     glAbstraction,
+  const Graphics::FramebufferCreateInfo& createInfo)
+: mGl(glAbstraction),
+  mCallStack(callStack)
+{
+  mCreateInfo.colorAttachments       = std::move(createInfo.colorAttachments);
+  mCreateInfo.depthStencilAttachment = createInfo.depthStencilAttachment;
+  mCreateInfo.size                   = createInfo.size;
+}
+
+TestGraphicsFramebuffer::~TestGraphicsFramebuffer()
+{
+  if(mId)
+  {
+    mGl.DeleteFramebuffers(1, &mId);
+  }
+}
+
+void TestGraphicsFramebuffer::Initialize()
+{
+  mCallStack.PushCall("Initialize", "");
+
+  mGl.GenFramebuffers(1, &mId);
+  mGl.BindFramebuffer(GL_FRAMEBUFFER, mId);
+
+  for(Graphics::ColorAttachment& attachment : mCreateInfo.colorAttachments)
+  {
+    AttachTexture(attachment.texture, COLOR_ATTACHMENTS[attachment.attachmentId], attachment.layerId, attachment.levelId);
+  }
+  mGl.DrawBuffers(mCreateInfo.colorAttachments.size(), COLOR_ATTACHMENTS);
+
+  if(mCreateInfo.depthStencilAttachment.depthTexture)
+  {
+    // Create a depth or depth/stencil render target.
+    auto depthTexture = Uncast<TestGraphicsTexture>(mCreateInfo.depthStencilAttachment.depthTexture);
+    auto attachmentId = DEPTH_STENCIL_ATTACHMENT_TYPE(depthTexture->GetFormat()).attachment;
+
+    mGl.GenRenderbuffers(1, &mDepthBuffer);
+    mGl.BindRenderbuffer(GL_RENDERBUFFER, mDepthBuffer);
+    mGl.RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, mCreateInfo.size.width, mCreateInfo.size.height);
+    mGl.FramebufferRenderbuffer(GL_FRAMEBUFFER, attachmentId, GL_RENDERBUFFER, mDepthBuffer);
+
+    AttachTexture(depthTexture, attachmentId, 0, mCreateInfo.depthStencilAttachment.depthLevel);
+  }
+
+  if(mCreateInfo.depthStencilAttachment.stencilTexture)
+  {
+    auto stencilTexture = Uncast<TestGraphicsTexture>(mCreateInfo.depthStencilAttachment.stencilTexture);
+    auto attachmentId   = DEPTH_STENCIL_ATTACHMENT_TYPE(stencilTexture->GetFormat()).attachment;
+
+    // Create a stencil render target.
+    mGl.GenRenderbuffers(1, &mStencilBuffer);
+    mGl.BindRenderbuffer(GL_RENDERBUFFER, mStencilBuffer);
+    mGl.RenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, mCreateInfo.size.width, mCreateInfo.size.height);
+    mGl.FramebufferRenderbuffer(GL_FRAMEBUFFER, attachmentId, GL_RENDERBUFFER, mStencilBuffer);
+
+    AttachTexture(stencilTexture, attachmentId, 0, mCreateInfo.depthStencilAttachment.stencilLevel);
+  }
+  mGl.BindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+void TestGraphicsFramebuffer::AttachTexture(Graphics::Texture* texture, uint32_t attachmentId, uint32_t layerId, uint32_t levelId)
+{
+  auto graphicsTexture = Uncast<TestGraphicsTexture>(texture);
+  if(graphicsTexture->GetType() == Graphics::TextureType::TEXTURE_2D)
+  {
+    mGl.FramebufferTexture2D(GL_FRAMEBUFFER, attachmentId, graphicsTexture->GetTarget(), graphicsTexture->mId, levelId);
+  }
+  else
+  {
+    mGl.FramebufferTexture2D(GL_FRAMEBUFFER, attachmentId, GL_TEXTURE_CUBE_MAP_POSITIVE_X + layerId, graphicsTexture->mId, levelId);
+  }
+}
+
+void TestGraphicsFramebuffer::Bind()
+{
+  mCallStack.PushCall("Bind", "");
+
+  if(!mId)
+  {
+    Initialize();
+  }
+  mGl.BindFramebuffer(GL_FRAMEBUFFER, mId);
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-framebuffer.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-framebuffer.h
new file mode 100644 (file)
index 0000000..97efe39
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef TEST_GRAPHICS_FRAMEBUFFER_H
+#define TEST_GRAPHICS_FRAMEBUFFER_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/graphics-api/graphics-framebuffer-create-info.h>
+#include <dali/graphics-api/graphics-framebuffer.h>
+#include <dali/graphics-api/graphics-types.h>
+#include "test-gl-abstraction.h"
+#include "test-trace-call-stack.h"
+
+namespace Dali
+{
+class TestGraphicsFramebuffer : public Graphics::Framebuffer
+{
+public:
+  TestGraphicsFramebuffer(TraceCallStack& callStack, TestGlAbstraction& glAbstraction, const Graphics::FramebufferCreateInfo& createInfo);
+  ~TestGraphicsFramebuffer();
+
+  void Initialize();
+  void AttachTexture(Graphics::Texture* texture, uint32_t attachmentId, uint32_t layerId, uint32_t levelId);
+  void Bind();
+
+  TestGlAbstraction&              mGl;
+  Graphics::FramebufferCreateInfo mCreateInfo;
+  TraceCallStack&                 mCallStack;
+
+  GLuint mId{0};
+  GLuint mDepthBuffer{0};
+  GLuint mStencilBuffer{0};
+};
+
+} // namespace Dali
+
+#endif //TEST_GRAPHICS_FRAMEBUFFER_H
index d303d56..9e80f8f 100644 (file)
@@ -21,7 +21,7 @@ namespace Dali
 TestGraphicsPipeline::TestGraphicsPipeline(TestGlAbstraction& gl, const Graphics::PipelineCreateInfo& createInfo)
 : mGl(gl)
 {
-  // Need to deep copy, otherwise pointed at memory will go out of scope. Probably should do something about this.
+  // Need to deep copy, otherwise pointed at memory will go out of scope. @todo Probably should do something about this.
 
   if(createInfo.colorBlendState)
     colorBlendState = *createInfo.colorBlendState;
@@ -32,9 +32,6 @@ TestGraphicsPipeline::TestGraphicsPipeline(TestGlAbstraction& gl, const Graphics
   if(createInfo.viewportState)
     viewportState = *createInfo.viewportState;
 
-  if(createInfo.framebufferState)
-    framebufferState = *createInfo.framebufferState;
-
   if(createInfo.depthStencilState)
     depthStencilState = *createInfo.depthStencilState;
 
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-render-pass.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-render-pass.h
new file mode 100644 (file)
index 0000000..b52dd2d
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef DALI_TEST_GRAPHICS_RENDER_PASS_H
+#define DALI_TEST_GRAPHICS_RENDER_PASS_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/graphics-api/graphics-render-pass-create-info.h>
+#include <dali/graphics-api/graphics-render-pass.h>
+
+namespace Dali
+{
+class TestGraphicsRenderPass : public Graphics::RenderPass
+{
+public:
+  TestGraphicsRenderPass(TestGlAbstraction& gl, Graphics::RenderPassCreateInfo createInfo)
+  : mGl(gl)
+  {
+    attachments = *createInfo.attachments; // Deep copy the vector's contents... @todo FIXME!
+  }
+  ~TestGraphicsRenderPass() = default;
+
+  TestGlAbstraction&                           mGl;
+  std::vector<Graphics::AttachmentDescription> attachments;
+};
+
+} // namespace Dali
+
+#endif //DALI_TEST_GRAPHICS_RENDER_PASS_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-render-target.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-render-target.h
new file mode 100644 (file)
index 0000000..1ad7a5a
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef DALI_TEST_GRAPHICS_RENDER_TARGET_H
+#define DALI_TEST_GRAPHICS_RENDER_TARGET_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/graphics-api/graphics-render-target-create-info.h>
+#include <dali/graphics-api/graphics-render-target.h>
+
+namespace Dali
+{
+class TestGraphicsRenderTarget : public Graphics::RenderTarget
+{
+public:
+  TestGraphicsRenderTarget(TestGlAbstraction& gl, Graphics::RenderTargetCreateInfo createInfo)
+  : mGl(gl)
+  {
+    mCreateInfo.surface      = createInfo.surface;
+    mCreateInfo.framebuffer  = createInfo.framebuffer;
+    mCreateInfo.extent       = createInfo.extent;
+    mCreateInfo.preTransform = createInfo.preTransform;
+  }
+  ~TestGraphicsRenderTarget() = default;
+
+  TestGlAbstraction&               mGl;
+  Graphics::RenderTargetCreateInfo mCreateInfo;
+};
+
+} // namespace Dali
+
+#endif //DALI_TEST_GRAPHICS_RENDER_TARGET_H
  *
  */
 
-#include "test-gl-sync-abstraction.h"
+#include "test-graphics-sync-impl.h"
 
 namespace Dali
 {
-TestSyncObject::TestSyncObject(TraceCallStack& trace)
+TestSyncObject::TestSyncObject(Dali::TraceCallStack& trace)
+
 : synced(false),
   mTrace(trace)
 {
+  mTrace.PushCall("TestSyncObject cons", ""); // Trace the method
 }
 
 TestSyncObject::~TestSyncObject()
 {
+  mTrace.PushCall("TestSyncObject dstr", ""); // Trace the method
 }
 
 bool TestSyncObject::IsSynced()
@@ -35,7 +38,7 @@ bool TestSyncObject::IsSynced()
   return synced;
 }
 
-TestGlSyncAbstraction::TestGlSyncAbstraction()
+TestGraphicsSyncImplementation::TestGraphicsSyncImplementation()
 {
   Initialize();
 }
@@ -43,7 +46,7 @@ TestGlSyncAbstraction::TestGlSyncAbstraction()
 /**
  * Destructor
  */
-TestGlSyncAbstraction::~TestGlSyncAbstraction()
+TestGraphicsSyncImplementation::~TestGraphicsSyncImplementation()
 {
   for(SyncIter iter = mSyncObjects.begin(), end = mSyncObjects.end(); iter != end; ++iter)
   {
@@ -52,18 +55,14 @@ TestGlSyncAbstraction::~TestGlSyncAbstraction()
 }
 
 /**
- * Initialize the sync objects - clear down the map
+ * Initialize the sync objects
  */
-void TestGlSyncAbstraction::Initialize()
+void TestGraphicsSyncImplementation::Initialize()
 {
   mSyncObjects.clear();
 }
 
-/**
- * Create a sync object
- * @return the sync object
- */
-Integration::GlSyncAbstraction::SyncObject* TestGlSyncAbstraction::CreateSyncObject()
+Integration::GraphicsSyncAbstraction::SyncObject* TestGraphicsSyncImplementation::CreateSyncObject()
 {
   mTrace.PushCall("CreateSyncObject", ""); // Trace the method
 
@@ -76,7 +75,7 @@ Integration::GlSyncAbstraction::SyncObject* TestGlSyncAbstraction::CreateSyncObj
  * Destroy a sync object
  * @param[in] syncObject The object to destroy
  */
-void TestGlSyncAbstraction::DestroySyncObject(Integration::GlSyncAbstraction::SyncObject* syncObject)
+void TestGraphicsSyncImplementation::DestroySyncObject(Integration::GraphicsSyncAbstraction::SyncObject* syncObject)
 {
   std::stringstream out;
   out << syncObject;
@@ -93,7 +92,7 @@ void TestGlSyncAbstraction::DestroySyncObject(Integration::GlSyncAbstraction::Sy
   }
 }
 
-Integration::GlSyncAbstraction::SyncObject* TestGlSyncAbstraction::GetLastSyncObject()
+Integration::GraphicsSyncAbstraction::SyncObject* TestGraphicsSyncImplementation::GetLastSyncObject()
 {
   if(!mSyncObjects.empty())
   {
@@ -107,7 +106,7 @@ Integration::GlSyncAbstraction::SyncObject* TestGlSyncAbstraction::GetLastSyncOb
  * @param[in]
  * @param[in] sync The sync value to set
  */
-void TestGlSyncAbstraction::SetObjectSynced(Integration::GlSyncAbstraction::SyncObject* syncObject, bool sync)
+void TestGraphicsSyncImplementation::SetObjectSynced(Integration::GraphicsSyncAbstraction::SyncObject* syncObject, bool sync)
 {
   TestSyncObject* testSyncObject = static_cast<TestSyncObject*>(syncObject);
   testSyncObject->synced         = sync;
@@ -116,7 +115,7 @@ void TestGlSyncAbstraction::SetObjectSynced(Integration::GlSyncAbstraction::Sync
 /**
  * Turn trace on
  */
-void TestGlSyncAbstraction::EnableTrace(bool enable)
+void TestGraphicsSyncImplementation::EnableTrace(bool enable)
 {
   mTrace.Enable(enable);
 }
@@ -124,7 +123,7 @@ void TestGlSyncAbstraction::EnableTrace(bool enable)
 /**
  * Reset the trace callstack
  */
-void TestGlSyncAbstraction::ResetTrace()
+void TestGraphicsSyncImplementation::ResetTrace()
 {
   mTrace.Reset();
 }
@@ -132,12 +131,12 @@ void TestGlSyncAbstraction::ResetTrace()
 /**
  * Get the trace object (allows test case to find methods on it)
  */
-TraceCallStack& TestGlSyncAbstraction::GetTrace()
+TraceCallStack& TestGraphicsSyncImplementation::GetTrace()
 {
   return mTrace;
 }
 
-int32_t TestGlSyncAbstraction::GetNumberOfSyncObjects()
+int32_t TestGraphicsSyncImplementation::GetNumberOfSyncObjects()
 {
   return static_cast<int32_t>(mSyncObjects.size());
 }
@@ -1,5 +1,5 @@
-#ifndef TEST_GL_SYNC_ABSTRACTION_H
-#define TEST_GL_SYNC_ABSTRACTION_H
+#ifndef TEST_SYNC_IMPLEMENTATION_H
+#define TEST_SYNC_IMPLEMENTATION_H
 
 /*
  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
 #include <string>
 
 // INTERNAL INCLUDES
+#include <dali/graphics-api/graphics-sync-object-create-info.h>
+#include <dali/graphics-api/graphics-sync-object.h>
 #include <dali/integration-api/core.h>
-#include <dali/integration-api/gl-sync-abstraction.h>
+#include <dali/integration-api/graphics-sync-abstraction.h>
 
 #include "test-trace-call-stack.h"
 
 namespace Dali
 {
-class DALI_CORE_API TestSyncObject : public Integration::GlSyncAbstraction::SyncObject
+class TestGraphicsSyncImplementation;
+
+class TestSyncObject : public Integration::GraphicsSyncAbstraction::SyncObject
 {
 public:
   TestSyncObject(TraceCallStack& trace);
@@ -42,47 +46,45 @@ public:
 };
 
 /**
- * Class to emulate the GL sync functions with tracing
+ * Class to emulate the gpu sync functions with tracing
  */
-class DALI_CORE_API TestGlSyncAbstraction : public Integration::GlSyncAbstraction
+class TestGraphicsSyncImplementation : public Integration::GraphicsSyncAbstraction
 {
 public:
   /**
    * Constructor
    */
-  TestGlSyncAbstraction();
+  TestGraphicsSyncImplementation();
 
   /**
    * Destructor
    */
-  ~TestGlSyncAbstraction() override;
+  virtual ~TestGraphicsSyncImplementation();
 
   /**
-   * Initialize the sync objects - clear down the map
+   * Initialize the sync objects
    */
   void Initialize();
 
   /**
-   * Create a sync object
-   * @return the sync object
+   * Create a sync object that can be polled
    */
-  Integration::GlSyncAbstraction::SyncObject* CreateSyncObject() override;
+  GraphicsSyncAbstraction::SyncObject* CreateSyncObject() override;
 
   /**
    * Destroy a sync object
-   * @param[in] syncObject The object to destroy
    */
-  void DestroySyncObject(Integration::GlSyncAbstraction::SyncObject* syncObject) override;
+  void DestroySyncObject(GraphicsSyncAbstraction::SyncObject* syncObject) override;
 
 public: // TEST FUNCTIONS
-  Integration::GlSyncAbstraction::SyncObject* GetLastSyncObject();
+  GraphicsSyncAbstraction::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);
+  void SetObjectSynced(GraphicsSyncAbstraction::SyncObject* syncObject, bool sync);
 
   /**
    * Turn trace on
@@ -106,10 +108,10 @@ public: // TEST FUNCTIONS
    */
   int32_t GetNumberOfSyncObjects();
 
-private:
-  TestGlSyncAbstraction(const TestGlSyncAbstraction&);            ///< Undefined
-  TestGlSyncAbstraction& operator=(const TestGlSyncAbstraction&); ///< Undefined
+  TestGraphicsSyncImplementation(const TestGraphicsSyncImplementation&) = delete;
+  TestGraphicsSyncImplementation& operator=(const TestGraphicsSyncImplementation&) = delete;
 
+private:
   typedef std::vector<TestSyncObject*> SyncContainer;
   typedef SyncContainer::iterator      SyncIter;
   SyncContainer                        mSyncObjects;       ///< The sync objects
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-object.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-object.cpp
new file mode 100644 (file)
index 0000000..cf9b3c9
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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-graphics-sync-object.h"
+
+namespace Dali
+{
+TestGraphicsSyncObject::TestGraphicsSyncObject(TestGraphicsSyncImplementation& syncImpl, const Graphics::SyncObjectCreateInfo& createInfo)
+: mSyncImplementation(syncImpl),
+  mSyncObject(nullptr),
+  mCreateInfo(createInfo)
+{
+}
+
+TestGraphicsSyncObject::~TestGraphicsSyncObject()
+{
+  mSyncImplementation.DestroySyncObject(mSyncObject);
+}
+
+void TestGraphicsSyncObject::InitializeResource()
+{
+  mSyncObject = static_cast<TestSyncObject*>(mSyncImplementation.CreateSyncObject());
+}
+
+bool TestGraphicsSyncObject::IsSynced()
+{
+  bool synced = false;
+  if(mSyncObject)
+  {
+    synced = mSyncObject->IsSynced();
+  }
+  return synced;
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-object.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-object.h
new file mode 100644 (file)
index 0000000..c33de6c
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef DALI_TEST_GRAPHICS_SYNC_OBJECT_H_
+#define DALI_TEST_GRAPHICS_SYNC_OBJECT_H_
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/graphics-api/graphics-sync-object-create-info.h>
+#include <dali/graphics-api/graphics-sync-object.h>
+
+#include <test-graphics-sync-impl.h>
+
+namespace Dali
+{
+class TestGraphicsSyncObject : public Graphics::SyncObject
+{
+public:
+  TestGraphicsSyncObject(TestGraphicsSyncImplementation& syncImpl, const Graphics::SyncObjectCreateInfo& createInfo);
+  ~TestGraphicsSyncObject() override;
+  void InitializeResource();
+  bool IsSynced() override;
+
+public:
+  TestGraphicsSyncImplementation& mSyncImplementation;
+  TestSyncObject*                 mSyncObject;
+  Graphics::SyncObjectCreateInfo  mCreateInfo;
+};
+
+} // namespace Dali
+
+#endif //DALI_TEST_GRAPHICS_SYNC_OBJECT_H
index adeeeca..9e1ad3e 100644 (file)
@@ -183,6 +183,7 @@ bool IsCompressedFormat(Graphics::Format pixelFormat)
     case Graphics::Format::R64G64B64A64_SINT:
     case Graphics::Format::R64G64B64A64_SFLOAT:
     case Graphics::Format::B10G11R11_UFLOAT_PACK32:
+    case Graphics::Format::R11G11B10_UFLOAT_PACK32:
     case Graphics::Format::E5B9G9R9_UFLOAT_PACK32:
     case Graphics::Format::D16_UNORM:
     case Graphics::Format::X8_D24_UNORM_PACK32:
@@ -618,6 +619,12 @@ void PixelFormatToGl(Graphics::Format pixelFormat, GLenum& glFormat, GLint& glIn
       glFormat = 0;
       break;
     }
+    case Graphics::Format::R11G11B10_UFLOAT_PACK32:
+    {
+      glFormat      = GL_RGB;
+      pixelDataType = GL_FLOAT;
+      break;
+    }
 
     case Graphics::Format::R4G4_UNORM_PACK8:
     case Graphics::Format::A1R5G5B5_UNORM_PACK16:
@@ -768,6 +775,7 @@ void PixelFormatToGl(Graphics::Format pixelFormat, GLenum& glFormat, GLint& glIn
   {
     case Graphics::Format::R16G16B16A16_SFLOAT:
     case Graphics::Format::R32G32B32A32_SFLOAT:
+    case Graphics::Format::R11G11B10_UFLOAT_PACK32:
     {
       glInternalFormat = GL_R11F_G11F_B10F;
       break;
index 3eb54d3..58f7738 100644 (file)
@@ -49,6 +49,22 @@ public:
   GLuint GetTarget();
 
   /**
+   * Get the texture type
+   */
+  Graphics::TextureType GetType()
+  {
+    return mCreateInfo.textureType;
+  }
+
+  /**
+   * Get the texture format
+   */
+  Graphics::Format GetFormat()
+  {
+    return mCreateInfo.format;
+  }
+
+  /**
    * Bind this texture, ensure Native image is initialized if necessary.
    */
   void Bind(uint32_t textureUnit);
index 86b3bd9..0cfdcc0 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_SCENE_HOLDER_IMPL_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -51,7 +51,11 @@ public:
 
   bool PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect  ) override { return false; };
 
-  void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects ) override {};
+  void PostRender()
+  {
+  }
+
+  //void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects ) override {};
 
   void StopRender() override {};
 
index 48173fd..e309bfe 100644 (file)
@@ -45,6 +45,12 @@ ToolkitTestApplication::ToolkitTestApplication( size_t surfaceWidth, size_t surf
   mScene = AdaptorImpl::GetScene( *mMainWindow );
   mScene.SetDpi( Vector2( horizontalDpi, verticalDpi ) );
 
+  // Create render target for the scene
+  Graphics::RenderTargetCreateInfo rtInfo{};
+  rtInfo.SetExtent( {mSurfaceWidth, mSurfaceHeight });
+  mRenderTarget = mGraphicsController.CreateRenderTarget( rtInfo, nullptr );
+  mScene.SetSurfaceRenderTarget( mRenderTarget.get() );
+
   // Core needs to be initialized next before we start the adaptor
   InitializeCore();
   Accessibility::Accessible::SetObjectRegistry(mCore->GetObjectRegistry());
index 18ce2ef..474706f 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,8 @@
 #include <toolkit-vector-animation-renderer.h>
 #include <toolkit-event-thread-callback.h>
 #include <memory>
+#include <thread>
+#include <chrono>
 
 namespace Dali
 {
@@ -31,6 +33,11 @@ namespace Internal
 namespace Adaptor
 {
 
+namespace
+{
+Dali::Internal::Adaptor::VectorAnimationRenderer* gVectorAnimationRenderer = nullptr;
+}
+
 class VectorAnimationRenderer: public Dali::BaseObject
 {
 public:
@@ -40,8 +47,12 @@ public:
     mRenderer(),
     mWidth( 0 ),
     mHeight( 0 ),
+    mTotalFrameNumber(VECTOR_ANIMATION_TOTAL_FRAME_NUMBER),
     mPreviousFrame( 0 ),
+    mDelayTime(0),
+    mDroppedFrames(0),
     mFrameRate( 60.0f ),
+    mNeedDroppedFrames(false),
     mEventThreadCallback( new EventThreadCallback( MakeCallback( this, &VectorAnimationRenderer::OnTriggered ) ) )
   {
     mCount++;
@@ -60,10 +71,15 @@ public:
   bool Load(const std::string& url)
   {
     mUrl = url;
-    if(mUrl == "invalid.json")
+    if(mUrl == "invalid.json" || mUrl == "invalid.riv")
     {
       return false;
     }
+    else if(mUrl == "framedrop.json")
+    {
+      // Change total frame number for test
+      mTotalFrameNumber = 200;
+    }
     return true;
   }
 
@@ -96,6 +112,19 @@ public:
 
   bool Render( uint32_t frameNumber )
   {
+    if(mDelayTime != 0)
+    {
+      std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int32_t>(mDelayTime)));
+      mDelayTime = 0;
+      mNeedDroppedFrames = true;
+    }
+    else if(mNeedDroppedFrames)
+    {
+      mDroppedFrames = (frameNumber > mPreviousFrame) ? frameNumber - mPreviousFrame - 1: frameNumber + (mTotalFrameNumber - mPreviousFrame) - 1;
+      mNeedTrigger = true;
+      mNeedDroppedFrames = false;
+    }
+
     if( mNeedTrigger )
     {
       mEventThreadCallback->Trigger();
@@ -114,7 +143,7 @@ public:
 
   uint32_t GetTotalFrameNumber() const
   {
-    return VECTOR_ANIMATION_TOTAL_FRAME_NUMBER;
+    return mTotalFrameNumber;
   }
 
   float GetFrameRate() const
@@ -165,8 +194,12 @@ public:
   Dali::Renderer mRenderer;
   uint32_t mWidth;
   uint32_t mHeight;
+  uint32_t mTotalFrameNumber;
   uint32_t mPreviousFrame;
+  uint32_t mDelayTime;
+  uint32_t mDroppedFrames;
   float mFrameRate;
+  bool mNeedDroppedFrames;
   Dali::VectorAnimationRenderer::UploadCompletedSignalType mUploadCompletedSignal;
   std::unique_ptr< EventThreadCallback > mEventThreadCallback;
 };
@@ -201,6 +234,8 @@ VectorAnimationRenderer VectorAnimationRenderer::New()
 {
   Internal::Adaptor::VectorAnimationRenderer* animationRenderer = new Internal::Adaptor::VectorAnimationRenderer();
 
+  Internal::Adaptor::gVectorAnimationRenderer = animationRenderer;
+
   return VectorAnimationRenderer( animationRenderer );
 }
 
@@ -293,6 +328,16 @@ void RequestTrigger()
   Dali::Internal::Adaptor::VectorAnimationRenderer::mNeedTrigger = true;
 }
 
+void DelayRendering(uint32_t delay)
+{
+  Dali::Internal::Adaptor::gVectorAnimationRenderer->mDelayTime = delay;
+}
+
+uint32_t GetDroppedFrames()
+{
+  return Dali::Internal::Adaptor::gVectorAnimationRenderer->mDroppedFrames;
+}
+
 } // VectorAnimationRenderer
 } // Test
 
index 2213465..a1ea51b 100755 (executable)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_TEST_VECTOR_ANIMATION_RENDERER_H
 
 /*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,6 +32,8 @@ namespace VectorAnimationRenderer
 #define VECTOR_ANIMATION_MARKER_END_FRAME_2 3
 
 void RequestTrigger();
+void DelayRendering(uint32_t delay);
+uint32_t GetDroppedFrames();
 
 } // VectorAnimationRenderer
 } // Test
index 88be84c..b30d3b6 100755 (executable)
@@ -841,11 +841,11 @@ public:
 
   Dali::PixelData GetImageBuffer() override
   {
-    uint8_t* faviconData = new uint8_t[ 16 ];
-    memset(faviconData, 0xff, 16);
-    return Dali::PixelData::New( faviconData, 16, 2, 2,
-                                 Dali::Pixel::Format::RGBA8888,
-                                 Dali::PixelData::ReleaseFunction::DELETE_ARRAY );
+    uint8_t* imageData = new uint8_t[16];
+    memset(imageData, 0xff, 16);
+    return Dali::PixelData::New(imageData, 16, 2, 2,
+                                Dali::Pixel::Format::RGBA8888,
+                                Dali::PixelData::ReleaseFunction::DELETE_ARRAY);
   }
 
 private:
@@ -1229,28 +1229,20 @@ public:
 
   Dali::PixelData GetFavicon() const
   {
-    uint8_t* faviconData = new uint8_t[ 16 ];
-
-    faviconData[ 0 ] = 0xff;
-    faviconData[ 1 ] = 0x00;
-    faviconData[ 2 ] = 0x00;
-    faviconData[ 3 ] = 0xff;
-    faviconData[ 4 ] = 0xff;
-    faviconData[ 5 ] = 0x00;
-    faviconData[ 6 ] = 0x00;
-    faviconData[ 7 ] = 0xff;
-    faviconData[ 8 ] = 0xff;
-    faviconData[ 9 ] = 0x00;
-    faviconData[ 10 ] = 0x00;
-    faviconData[ 11 ] = 0xff;
-    faviconData[ 12 ] = 0xff;
-    faviconData[ 13 ] = 0x00;
-    faviconData[ 14 ] = 0x00;
-    faviconData[ 15 ] = 0xff;
-
-    return Dali::PixelData::New( faviconData, 16, 2, 2,
-                                 Dali::Pixel::Format::RGBA8888,
-                                 Dali::PixelData::ReleaseFunction::DELETE_ARRAY );
+    static int testGetFaviconCount = 0;
+    if (testGetFaviconCount == 0)
+    {
+      testGetFaviconCount++;
+      uint8_t* faviconData = new uint8_t[16];
+      memset(faviconData, 0xff, 16);
+      return Dali::PixelData::New(faviconData, 16, 2, 2,
+                                  Dali::Pixel::Format::RGBA8888,
+                                  Dali::PixelData::ReleaseFunction::DELETE_ARRAY);
+    }
+    else
+    {
+      return Dali::PixelData();
+    }
   }
 
   bool CanGoForward() const
@@ -1507,9 +1499,9 @@ public:
     return mConsoleMessageSignal;
   }
 
-  Dali::WebEnginePlugin::WebEnginePolicyDecisionSignalType& PolicyDecisionSignal()
+  Dali::WebEnginePlugin::WebEngineResponsePolicyDecisionSignalType& ResponsePolicyDecisionSignal()
   {
-    return mPolicyDecisionSignal;
+    return mResponsePolicyDecisionSignal;
   }
 
   Dali::WebEnginePlugin::WebEngineCertificateSignalType& CertificateConfirmSignal()
@@ -1552,7 +1544,7 @@ public:
   Dali::WebEnginePlugin::WebEngineFrameRenderedSignalType           mFrameRenderedSignal;
   Dali::WebEnginePlugin::WebEngineRequestInterceptorSignalType      mRequestInterceptorSignal;
   Dali::WebEnginePlugin::WebEngineConsoleMessageSignalType          mConsoleMessageSignal;
-  Dali::WebEnginePlugin::WebEnginePolicyDecisionSignalType          mPolicyDecisionSignal;
+  Dali::WebEnginePlugin::WebEngineResponsePolicyDecisionSignalType  mResponsePolicyDecisionSignal;
   Dali::WebEnginePlugin::WebEngineCertificateSignalType             mCertificateConfirmSignal;
   Dali::WebEnginePlugin::WebEngineCertificateSignalType             mSslCertificateChangedSignal;
   Dali::WebEnginePlugin::WebEngineHttpAuthHandlerSignalType         mHttpAuthHandlerSignal;
@@ -1636,7 +1628,7 @@ bool OnLoadUrl()
     std::shared_ptr<Dali::WebEngineConsoleMessage> message(new MockWebEngineConsoleMessage());
     gInstance->mConsoleMessageSignal.Emit(std::move(message));
     std::shared_ptr<Dali::WebEnginePolicyDecision> policyDecision(new MockWebEnginePolicyDecision());
-    gInstance->mPolicyDecisionSignal.Emit(std::move(policyDecision));
+    gInstance->mResponsePolicyDecisionSignal.Emit(std::move(policyDecision));
 
     std::shared_ptr<Dali::WebEngineCertificate> certificate(new MockWebEngineCertificate());
     gInstance->mCertificateConfirmSignal.Emit(std::move(certificate));
@@ -2322,9 +2314,9 @@ Dali::WebEnginePlugin::WebEngineConsoleMessageSignalType& WebEngine::ConsoleMess
   return Internal::Adaptor::GetImplementation(*this).ConsoleMessageSignal();
 }
 
-Dali::WebEnginePlugin::WebEnginePolicyDecisionSignalType& WebEngine::PolicyDecisionSignal()
+Dali::WebEnginePlugin::WebEngineResponsePolicyDecisionSignalType& WebEngine::ResponsePolicyDecisionSignal()
 {
-  return Internal::Adaptor::GetImplementation(*this).PolicyDecisionSignal();
+  return Internal::Adaptor::GetImplementation(*this).ResponsePolicyDecisionSignal();
 }
 
 Dali::WebEnginePlugin::WebEngineCertificateSignalType& WebEngine::CertificateConfirmSignal()
index 6d74b7c..56d67f4 100644 (file)
@@ -77,7 +77,10 @@ int UtcDaliAnimatedImageVisualGetPropertyMap01(void)
     .Add( ImageVisual::Property::WRAP_MODE_U, WrapMode::REPEAT )
     .Add( ImageVisual::Property::WRAP_MODE_V, WrapMode::DEFAULT )
     .Add( DevelVisual::Property::CORNER_RADIUS, 22.2f )
-    .Add( DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::ABSOLUTE ));
+    .Add( DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::ABSOLUTE )
+    .Add( DevelVisual::Property::BORDERLINE_WIDTH, 33.3f )
+    .Add( DevelVisual::Property::BORDERLINE_COLOR, Color::RED )
+    .Add( DevelVisual::Property::BORDERLINE_OFFSET, 0.3f ));
 
   Property::Map resultMap;
   animatedImageVisual.CreatePropertyMap( resultMap );
@@ -98,6 +101,18 @@ int UtcDaliAnimatedImageVisualGetPropertyMap01(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<int>() == Visual::Transform::Policy::ABSOLUTE );
 
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 33.3f, TEST_LOCATION );
+
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), Color::RED, TEST_LOCATION );
+
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 0.3f, TEST_LOCATION );
+
   // request AnimatedImageVisual with an URL
   Visual::Base animatedImageVisual2 = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() );
   resultMap.Clear();
@@ -137,7 +152,10 @@ int UtcDaliAnimatedImageVisualGetPropertyMap02(void)
     .Add( "wrapModeU", WrapMode::REPEAT )
     .Add( "wrapModeV", WrapMode::DEFAULT )
     .Add( "cornerRadius", Vector4(50.0f, 25.0f, 12.5f, 33.0f) )
-    .Add( "cornerRadiusPolicy", Visual::Transform::Policy::RELATIVE ));
+    .Add( "cornerRadiusPolicy", Visual::Transform::Policy::RELATIVE )
+    .Add( "borderlineWidth", 20.0f )
+    .Add( "borderlineColor", Vector4() )
+    .Add( "borderlineOffset", -1.0f));
 
   Property::Map resultMap;
   animatedImageVisual.CreatePropertyMap( resultMap );
@@ -180,6 +198,18 @@ int UtcDaliAnimatedImageVisualGetPropertyMap02(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<int>() == Visual::Transform::Policy::RELATIVE );
 
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, "borderlineWidth" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 20.0f, TEST_LOCATION );
+
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_COLOR, "borderlineColor" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), Vector4::ZERO, TEST_LOCATION );
+
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, "borderlineOffset" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), -1.0f, TEST_LOCATION );
+
   END_TEST;
 }
 
@@ -248,6 +278,18 @@ int UtcDaliAnimatedImageVisualGetPropertyMap03(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<int>() == Visual::Transform::Policy::ABSOLUTE );
 
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, "borderlineWidth" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 0.0f, TEST_LOCATION );
+
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_COLOR, "borderlineColor" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), Color::BLACK, TEST_LOCATION );
+
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, "borderlineOffset" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 0.0f, TEST_LOCATION );
+
   END_TEST;
 }
 
@@ -264,7 +306,8 @@ int UtcDaliAnimatedImageVisualGetPropertyMap04(void)
     .Add( ImageVisual::Property::URL, TEST_GIF_FILE_NAME )
     .Add( ImageVisual::Property::BATCH_SIZE, 1 )
     .Add( ImageVisual::Property::CACHE_SIZE, 1 )
-    .Add( ImageVisual::Property::SYNCHRONOUS_LOADING, false ));
+    .Add( ImageVisual::Property::SYNCHRONOUS_LOADING, false )
+    .Add( DevelVisual::Property::BORDERLINE_WIDTH, 0.4f ));
 
   Property::Map resultMap;
   animatedImageVisual.CreatePropertyMap( resultMap );
@@ -290,6 +333,18 @@ int UtcDaliAnimatedImageVisualGetPropertyMap04(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_EQUALS( value->Get<int>(), 4, TEST_LOCATION );
 
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, "borderlineWidth" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 0.4f, TEST_LOCATION );
+
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_COLOR, "borderlineColor" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), Vector4(0.0f, 0.0f, 0.0f, 1.0f), TEST_LOCATION );
+
+  value = resultMap.Find( Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, "borderlineOffset" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 0.0f, TEST_LOCATION );
+
   END_TEST;
 }
 
index dfd0b72..6159e71 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -50,8 +50,12 @@ namespace
 {
 
 const char* TEST_VECTOR_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR  "/insta_camera.json";
+const char* TEST_VECTOR_IMAGE_FILE_NAME_FRAME_DROP = "framedrop.json";
 const char* TEST_VECTOR_IMAGE_INVALID_FILE_NAME =  "invalid.json";
 
+const char* TEST_VECTOR_IMAGE_RIVE_FILE_NAME =  TEST_RESOURCE_DIR  "/shape.riv";
+const char* TEST_VECTOR_IMAGE_INVALID_RIVE_FILE_NAME = "invalid.riv";
+
 bool gAnimationFinishedSignalFired = false;
 
 void VisualEventSignal( Control control, Dali::Property::Index visualIndex, Dali::Property::Index signalId )
@@ -141,7 +145,8 @@ int UtcDaliVisualFactoryGetAnimatedVectorImageVisual03(void)
              .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME  )
              .Add( DevelImageVisual::Property::LOOP_COUNT, 3  )
              .Add( DevelImageVisual::Property::PLAY_RANGE, playRange  )
-             .Add( DevelVisual::Property::CORNER_RADIUS, 50.0f );
+             .Add( DevelVisual::Property::CORNER_RADIUS, 50.0f )
+             .Add( DevelVisual::Property::BORDERLINE_WIDTH, 20.0f );
 
   Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
   DALI_TEST_CHECK( visual );
@@ -173,6 +178,9 @@ int UtcDaliVisualFactoryGetAnimatedVectorImageVisual04(void)
 
   int startFrame = 1, endFrame = 3;
   float cornerRadius = 22.0f;
+  float borderlineWidth = 2.0f;
+  Vector4 borderlineColor = Vector4(1.0f, 1.0f, 1.0f, 1.0f);
+  float borderlineOffset = 0.1f;
   Property::Array playRange;
   playRange.PushBack( startFrame );
   playRange.PushBack( endFrame );
@@ -185,7 +193,10 @@ int UtcDaliVisualFactoryGetAnimatedVectorImageVisual04(void)
              .Add( "stopBehavior", DevelImageVisual::StopBehavior::FIRST_FRAME )
              .Add( "loopingMode", DevelImageVisual::LoopingMode::AUTO_REVERSE )
              .Add( "redrawInScalingDown", false )
-             .Add( "cornerRadius", cornerRadius );
+             .Add( "cornerRadius", cornerRadius )
+             .Add( "borderlineWidth", borderlineWidth )
+             .Add( "borderlineColor", borderlineColor )
+             .Add( "borderlineOffset", borderlineOffset );
 
   Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
   DALI_TEST_CHECK( visual );
@@ -249,6 +260,18 @@ int UtcDaliVisualFactoryGetAnimatedVectorImageVisual04(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get< int >() == Visual::Transform::Policy::ABSOLUTE );
 
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< float >(), borderlineWidth, TEST_LOCATION );
+
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< Vector4 >(), borderlineColor, TEST_LOCATION );
+
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< float >(), borderlineOffset, TEST_LOCATION );
+
   actor.Unparent( );
   DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
 
@@ -262,6 +285,9 @@ int UtcDaliAnimatedVectorImageVisualGetPropertyMap01(void)
 
   int startFrame = 1, endFrame = 3;
   Vector4 cornerRadius(50.0f, 22.0f, 0.0f, 3.0f);
+  float borderlineWidth = 2.3f;
+  Vector4 borderlineColor = Vector4(0.3f, 0.3f, 1.0f, 1.0f);
+  float borderlineOffset = 0.3f;
   Property::Array playRange;
   playRange.PushBack( startFrame );
   playRange.PushBack( endFrame );
@@ -272,7 +298,10 @@ int UtcDaliAnimatedVectorImageVisualGetPropertyMap01(void)
              .Add( DevelImageVisual::Property::LOOP_COUNT, 3 )
              .Add( DevelImageVisual::Property::PLAY_RANGE, playRange )
              .Add( DevelVisual::Property::CORNER_RADIUS, cornerRadius )
-             .Add( DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::RELATIVE);
+             .Add( DevelVisual::Property::CORNER_RADIUS_POLICY, Visual::Transform::Policy::RELATIVE)
+             .Add( DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth )
+             .Add( DevelVisual::Property::BORDERLINE_COLOR, borderlineColor )
+             .Add( DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset );
 
   // request AnimatedVectorImageVisual with a property map
   VisualFactory factory = VisualFactory::Get();
@@ -340,6 +369,18 @@ int UtcDaliAnimatedVectorImageVisualGetPropertyMap01(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get< int >() == Visual::Transform::Policy::RELATIVE );
 
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH, "borderlineWidth" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< float >(), borderlineWidth, TEST_LOCATION );
+
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< Vector4 >(), borderlineColor, TEST_LOCATION );
+
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< float >(), borderlineOffset, TEST_LOCATION );
+
   // request AnimatedVectorImageVisual with an URL
   Visual::Base visual2 = factory.CreateVisual( TEST_VECTOR_IMAGE_FILE_NAME, ImageDimensions() );
 
@@ -1530,3 +1571,244 @@ int UtcDaliAnimatedVectorImageVisualInvalidFile(void)
 
   END_TEST;
 }
+
+int UtcDaliAnimatedVectorImageVisualFrameDrops(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliAnimatedVectorImageVisualFrameDrops");
+
+  Property::Map propertyMap;
+  propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
+             .Add(ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME_FRAME_DROP);
+
+  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.SetProperty(Actor::Property::SIZE, controlSize);
+
+  application.GetScene().Add(actor);
+
+  application.SendNotification();
+  application.Render();
+
+  Property::Map attributes;
+  DevelControl::DoAction(actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes);
+
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 1 - render the first frame
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  // Make delay to drop frames
+  Test::VectorAnimationRenderer::DelayRendering(170); // longer than 16.6 * 10frames
+
+  // Check dropped frame
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  uint32_t frames = Test::VectorAnimationRenderer::GetDroppedFrames();
+  DALI_TEST_CHECK(frames >= 9);
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualLoadRiveFileP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualLoadRiveFile: Request animated vector image visual with a rive url" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base visual = factory.CreateVisual( TEST_VECTOR_IMAGE_RIVE_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.SetProperty( Actor::Property::SIZE, Vector2( 200.0f, 200.0f ) );
+  application.GetScene().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 SetOffScene().
+  actor.Unparent();
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualLoadRiveFileN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("Request loading with invalid rive file - should draw broken image");
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  Property::Map propertyMap;
+  propertyMap.Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
+             .Add(ImageVisual::Property::URL, TEST_VECTOR_IMAGE_INVALID_RIVE_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.SetProperty(Actor::Property::SIZE, Vector2(20.0f, 20.0f));
+
+  application.GetScene().Add(actor);
+
+  application.SendNotification();
+  application.Render();
+
+  // Check resource status
+  Visual::ResourceStatus status = actor.GetVisualResourceStatus(DummyControl::Property::TEST_VISUAL);
+  DALI_TEST_EQUALS(status, Visual::ResourceStatus::FAILED, TEST_LOCATION);
+
+  // The broken image should be shown.
+  DALI_TEST_EQUALS(actor.GetRendererCount(), 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualPlaybackRiveFile(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualPlaybackRiveFile" );
+
+  {
+    // request AnimatedVectorImageVisual for Rive 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_RIVE_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 );
+
+    application.GetScene().Add( dummyControl );
+    application.SendNotification();
+    application.Render( 16 );
+
+    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);
+
+    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" );
+    application.GetScene().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.SetProperty( Actor::Property::SIZE, newSize );
+
+    application.SendNotification();
+    application.Render(16);
+
+    // Size should be changed
+    Vector3 naturalSize = dummyControl.GetNaturalSize();
+    DALI_TEST_CHECK( naturalSize == newSize );
+
+    dummyControl.Unparent();
+  }
+
+  END_TEST;
+}
index 396bab4..221bac0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -525,22 +525,9 @@ int UtcDaliControlBackgroundColorRendererCount(void)
 
   ToolkitTestApplication application;
   Control control = Control::New();
+  control[Actor::Property::SIZE] = Vector2(100.0f, 100.0f);
   application.GetScene().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 );
@@ -561,19 +548,29 @@ int UtcDaliControlBackgroundColorRendererCount(void)
   DALI_TEST_EQUALS( GetControlBackgroundColor( control ), newColor, TEST_LOCATION );
   DALI_TEST_EQUALS( renderer, control.GetRendererAt( 0 ), TEST_LOCATION );
 
-  tet_infoline( "Set transparent, ensure no renderers are created" );
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& drawTrace = gl.GetDrawTrace();
+  drawTrace.Enable(true);
+
+  tet_infoline( "Set transparent, 1 renderer should be created, but ensure nothing is drawn" );
   control.SetBackgroundColor( Color::TRANSPARENT );
   application.SendNotification();
   application.Render();
-  DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
   DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
+  DALI_TEST_EQUALS(drawTrace.FindMethod("DrawArrays"), false, TEST_LOCATION);
+
+  drawTrace.Reset();
 
   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 );
+  DALI_TEST_EQUALS(drawTrace.FindMethod("DrawArrays"), true, TEST_LOCATION);
 
   tet_infoline( "Set a color, only 1 renderer should exist" );
   control.SetBackgroundColor( Color::RED );
@@ -595,12 +592,15 @@ int UtcDaliControlBackgroundColorRendererCount(void)
   DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
   DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
 
-  tet_infoline( "Disable clipping, no renderers" );
+  drawTrace.Reset();
+
+  tet_infoline( "Disable clipping, render nothing" );
   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 );
+  DALI_TEST_EQUALS(drawTrace.FindMethod("DrawArrays"), false, TEST_LOCATION);
 
   END_TEST;
 }
index 29faa6d..1cd3de5 100644 (file)
@@ -2743,7 +2743,7 @@ namespace
 
 static int gResourceReadySignalCounter = 0;
 
-void OnResourceReadySignal( Control control )
+void OnResourceReadySignal01( Control control )
 {
   gResourceReadySignalCounter++;
 
@@ -2764,7 +2764,7 @@ void OnResourceReadySignal( Control control )
   }
 }
 
-void OnResourceReadySignal01( Control control )
+void OnResourceReadySignal02( Control control )
 {
   if(++gResourceReadySignalCounter == 1)
   {
@@ -2776,6 +2776,34 @@ void OnResourceReadySignal01( Control control )
   }
 }
 
+ImageView gImageView1;
+ImageView gImageView2;
+ImageView gImageView3;
+
+void OnResourceReadySignal03( Control control )
+{
+  if(gResourceReadySignalCounter == 0)
+  {
+    // Queue loading
+    // 1. Use cached image, then UploadComplete will be called right after OnResourceReadySignal03.
+    gImageView2[ImageView::Property::IMAGE] = gImage_34_RGBA;
+
+    // 2. Load a new image
+    gImageView3[ImageView::Property::IMAGE] = TEST_IMAGE_1;
+
+    // 3. Use the new image again
+    gImageView1[ImageView::Property::IMAGE] = TEST_IMAGE_1;
+    gImageView1.ResourceReadySignal().Connect(&OnResourceReadySignal03);
+  }
+  else if(gResourceReadySignalCounter == 1)
+  {
+    // This is called from TextureManager::ProcessQueuedTextures().
+    gImageView1.Unparent();
+    gImageView1.Reset();
+  }
+  gResourceReadySignalCounter++;
+}
+
 }
 
 int UtcDaliImageViewSetImageOnResourceReadySignal01(void)
@@ -2787,7 +2815,7 @@ int UtcDaliImageViewSetImageOnResourceReadySignal01(void)
   gResourceReadySignalCounter = 0;
 
   ImageView imageView = ImageView::New( gImage_34_RGBA );
-  imageView.ResourceReadySignal().Connect( &OnResourceReadySignal );
+  imageView.ResourceReadySignal().Connect( &OnResourceReadySignal01 );
 
   application.GetScene().Add( imageView );
 
@@ -2829,7 +2857,7 @@ int UtcDaliImageViewSetImageOnResourceReadySignal02(void)
   gResourceReadySignalCounter = 0;
 
   ImageView imageView = ImageView::New( gImage_34_RGBA );
-  imageView.ResourceReadySignal().Connect( &OnResourceReadySignal01 );
+  imageView.ResourceReadySignal().Connect( &OnResourceReadySignal02 );
 
   application.GetScene().Add( imageView );
 
@@ -2847,3 +2875,32 @@ int UtcDaliImageViewSetImageOnResourceReadySignal02(void)
 
   END_TEST;
 }
+
+int UtcDaliImageViewSetImageOnResourceReadySignal03(void)
+{
+  tet_infoline("Test setting image from within signal handler.");
+
+  ToolkitTestApplication application;
+
+  gResourceReadySignalCounter = 0;
+
+  gImageView1 = ImageView::New(gImage_34_RGBA);
+  application.GetScene().Add(gImageView1);
+
+  // Wait for loading
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+
+  gImageView2 = ImageView::New(gImage_600_RGB);
+  gImageView2.ResourceReadySignal().Connect(&OnResourceReadySignal03);
+  application.GetScene().Add(gImageView2);
+
+  gImageView3 = ImageView::New();
+  application.GetScene().Add(gImageView3);
+
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
index e9bd76e..fdf1697 100644 (file)
@@ -24,6 +24,7 @@
 #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/public-api/image-loader/image.h>
 #include <dali-toolkit/dali-toolkit.h>
 #include "dummy-control.h"
 
@@ -416,6 +417,51 @@ int UtcDaliImageVisualRemoteImageLoad(void)
   END_TEST;
 }
 
+
+int UtcDaliImageVisualWithNativeImage(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Use Native Image as url" );
+
+  NativeImageSourcePtr nativeImageSource = NativeImageSource::New(500, 500, NativeImageSource::COLOR_DEPTH_DEFAULT);
+  std::string url = Dali::Toolkit::Image::GenerateUrl(nativeImageSource);
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  url );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  application.GetScene().Add( actor );
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Shader shader = renderer.GetShader();
+
+  Property::Value value = shader.GetProperty(Shader::Property::PROGRAM);
+  DALI_TEST_CHECK(value.GetType() == Property::MAP);
+  const Property::Map* outMap = value.GetMap();
+  std::string fragmentShader = (*outMap)["fragment"].Get<std::string>();
+
+  const char* fragmentPrefix = nativeImageSource->GetCustomFragmentPrefix();
+  size_t pos = fragmentShader.find(fragmentPrefix);
+
+  DALI_TEST_EQUALS( pos != std::string::npos, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
 int UtcDaliImageVisualTextureReuse1(void)
 {
   ToolkitTestApplication application;
index 720f596..be3cf44 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -1616,4 +1616,172 @@ int UtcDaliKeyboardFocusManagerFocusPerWindow(void)
   END_TEST;
 }
 
+int UtcDaliKeyboardFocusManagerWithoutFocusablePropertiesMoveFocus(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerWithoutFocusablePropertiesMoveFocus");
+
+  // 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();
+  PushButton button3 = PushButton::New();
+  PushButton button4 = PushButton::New();
+  PushButton button5 = PushButton::New();
+
+  button1.SetProperty( Actor::Property::SIZE, Vector2( 50, 50 ) );
+  button2.SetProperty( Actor::Property::SIZE, Vector2( 50, 50 ) );
+  button3.SetProperty( Actor::Property::SIZE, Vector2( 50, 50 ) );
+  button4.SetProperty( Actor::Property::SIZE, Vector2( 50, 50 ) );
+  button5.SetProperty( Actor::Property::SIZE, Vector2( 50, 50 ) );
+
+  button1.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true);
+  button2.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true);
+  button3.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true);
+  button4.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true);
+  button5.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true);
+
+  application.GetScene().Add(button1);
+  application.GetScene().Add(button2);
+  application.GetScene().Add(button3);
+  application.GetScene().Add(button4);
+  application.GetScene().Add(button5);
+
+  // set position
+  // button1 -- button2
+  //   |           |
+  //   |    button5|
+  // button3 -- button4
+  button1.SetProperty( Actor::Property::POSITION, Vector2(0.0f, 0.0f));
+  button2.SetProperty( Actor::Property::POSITION, Vector2(100.0f, 0.0f));
+  button3.SetProperty( Actor::Property::POSITION, Vector2(0.0f, 100.0f));
+  button4.SetProperty( Actor::Property::POSITION, Vector2(100.0f, 100.0f));
+  button5.SetProperty( Actor::Property::POSITION, Vector2(60.0f, 60.0f));
+
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  // Set the focus to the button1
+  // [button1] -- button2
+  //   |           |
+  //   |    button5|
+  // button3 -- button4
+  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();
+
+  // without set the navigation properties, but we can focus move
+
+  // Move the focus towards right
+  // button1 -- [button2]
+  //   |           |
+  //   |    button5|
+  // button3 -- button4
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == 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
+  // button1 -- button2
+  //   |           |
+  //   |  [button5]|
+  // button3 -- button4
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::DOWN) == true);
+
+  // Confirm whether focus is moved to button5
+  DALI_TEST_EQUALS(button5.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 == button5);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards right
+  // button1 -- button2
+  //   |           |
+  //   |    button5|
+  // button3 -- [button4]
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == true);
+
+  // Confirm whether focus is moved to button4
+  DALI_TEST_EQUALS(button4.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button5);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button4);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards left
+  // button1 -- button2
+  //   |           |
+  //   |  [button5]|
+  // button3 -- button4
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == true);
+
+  // Confirm whether focus is moved to button5
+  DALI_TEST_EQUALS(button5.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button4);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button5);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards left
+  // button1 -- button2
+  //   |           |
+  //   |    button5|
+  //[button3] -- button4
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == true);
+
+  // Confirm whether focus is moved to button3
+  DALI_TEST_EQUALS(button3.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button5);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button3);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards up
+  //[button1]-- button2
+  //   |           |
+  //   |    button5|
+  // button3 -- button4
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::UP) == 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 == button3);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button1);
+  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);
+
+  // Move the focus toward page up/down. The focus move will fail as invalid direction.
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::PAGE_UP) == false);
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::PAGE_DOWN) == false);
+  focusChangedCallback.Reset();
+
+  END_TEST;
+}
 
index 62625ef..675e2c7 100644 (file)
@@ -28,6 +28,7 @@
 #include <dali-toolkit/dali-toolkit.h>
 #include <dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h>
 #include <dali-toolkit/devel-api/text/rendering-backend.h>
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
 
 using namespace Dali;
 using namespace Toolkit;
@@ -104,7 +105,8 @@ const char* const PROPERTY_NAME_MATCH_SYSTEM_LANGUAGE_DIRECTION      = "matchSys
 const char* const PROPERTY_NAME_MAX_LENGTH                           = "maxLength";
 const char* const PROPERTY_NAME_FONT_SIZE_SCALE                      = "fontSizeScale";
 const char* const PROPERTY_NAME_GRAB_HANDLE_COLOR                    = "grabHandleColor";
-
+const char* const PROPERTY_NAME_ENABLE_GRAB_HANDLE_POPUP             = "enableGrabHandlePopup";
+const char* const PROPERTY_NAME_INPUT_METHOD_SETTINGS                = "inputMethodSettings";
 
 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.
@@ -511,7 +513,8 @@ int UtcDaliTextEditorGetPropertyP(void)
   DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_MATCH_SYSTEM_LANGUAGE_DIRECTION ) == DevelTextEditor::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION );
   DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_MAX_LENGTH ) == DevelTextEditor::Property::MAX_LENGTH );
   DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_GRAB_HANDLE_COLOR ) == DevelTextEditor::Property::GRAB_HANDLE_COLOR );
-
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_ENABLE_GRAB_HANDLE_POPUP ) == DevelTextEditor::Property::ENABLE_GRAB_HANDLE_POPUP );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_METHOD_SETTINGS ) == DevelTextEditor::Property::INPUT_METHOD_SETTINGS );
 
   END_TEST;
 }
@@ -930,6 +933,42 @@ int UtcDaliTextEditorSetPropertyP(void)
   editor.SetProperty( DevelTextEditor::Property::GRAB_HANDLE_COLOR, Color::GREEN );
   DALI_TEST_EQUALS( editor.GetProperty<Vector4>( DevelTextEditor::Property::GRAB_HANDLE_COLOR ), Color::GREEN, TEST_LOCATION );
 
+  // Test the ENABLE_GRAB_HANDLE_POPUP property
+  editor.SetProperty( DevelTextEditor::Property::ENABLE_GRAB_HANDLE_POPUP, false );
+  DALI_TEST_EQUALS( editor.GetProperty<bool>( DevelTextEditor::Property::ENABLE_GRAB_HANDLE_POPUP ), false, 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;
+  editor.SetProperty( DevelTextEditor::Property::INPUT_METHOD_SETTINGS, propertyMap );
+
+  Property::Value value = editor.GetProperty( DevelTextEditor::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 );
+
   application.SendNotification();
   application.Render();
 
@@ -3480,6 +3519,49 @@ int utcDaliTextEditorGetHeightForWidthDoesNotChangeLineCountLineWrapCharCase(voi
   END_TEST;
 }
 
+int utcDaliTextEditorGetHeightForWidthChangeLineCountWhenTextChanged(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" utcDaliTextEditorGetHeightForWidthChangeLineCountWhenTextChanged ");
+
+  int lineCountBefore =0 ;
+  int lineCountAfter =0 ;
+
+  // Create a text editor
+  TextEditor textEditor = TextEditor::New();
+  //Set very large font-size using point-size
+  textEditor.SetProperty( TextEditor::Property::POINT_SIZE, 10) ;
+  //Specify font-family
+  textEditor.SetProperty( TextEditor::Property::FONT_FAMILY, "DejaVu Sans");
+  //Specify size
+  textEditor.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 100.f ) );
+  //Set text longer than width of textEditor
+  textEditor.SetProperty( TextEditor::Property::TEXT, "Short text");
+  //Set line wrap mode Character
+  textEditor.SetProperty(TextEditor::Property::LINE_WRAP_MODE, "CHARACTER");
+
+  application.GetScene().Add( textEditor );
+
+  application.SendNotification();
+  application.Render();
+
+
+  lineCountBefore =  textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+
+  textEditor.SetProperty( TextEditor::Property::TEXT, "This is very loooooooooooooooooooooooooooooooooooong text for test");
+  lineCountAfter =  textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+
+  // When the text changed, the Line-count should be updated according to new text.
+  // Because the GetHeightForWidth is called in Controller::GetLineCount(float width)
+  DALI_TEST_EQUALS( lineCountBefore ,1, TEST_LOCATION );
+  DALI_TEST_GREATER( lineCountAfter,1, TEST_LOCATION );
+
+
+  END_TEST;
+}
+
+
 int utcDaliTextEditorGetNaturalSizeDoesNotChangeLineCountScrollingCase(void)
 {
   ToolkitTestApplication application;
@@ -3570,4 +3652,122 @@ int utcDaliTextEditorGetNaturalSizeDoesNotChangeLineCountLineWrapCharCase(void)
   DALI_TEST_EQUALS( lineCountAfter , lineCountBefore, TEST_LOCATION );
 
   END_TEST;
+}
+
+int UtcDaliTextEditorAtlasLimitationIsEnabledForLargeFontPointSize(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextEditorAtlasLimitationIsEnabledForLargeFontPointSize ");
+
+  // +2: First one to handle the equal case. Second one to handle odd to even case of GetNaturalSize
+  const uint32_t lessThanWidth = TextAbstraction::FontClient::MAX_TEXT_ATLAS_WIDTH - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+  const uint32_t lessThanHeight = TextAbstraction::FontClient::MAX_TEXT_ATLAS_HEIGHT - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+
+  // Create a text editor
+  TextEditor textEditor = TextEditor::New();
+
+  //Set size to avoid automatic eliding
+  textEditor.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+  //Set very large font-size using point-size
+  textEditor.SetProperty( TextEditor::Property::POINT_SIZE, 1000) ;
+  //Specify font-family
+  textEditor.SetProperty( TextEditor::Property::FONT_FAMILY, "DejaVu Sans");
+  //Set text to check if appear or not
+  textEditor.SetProperty( TextEditor::Property::TEXT, "A");
+
+  application.GetScene().Add( textEditor );
+
+  application.SendNotification();
+  application.Render();
+  //Use GetNaturalSize to verify that size of block does not exceed Atlas size
+  Vector3 naturalSize = textEditor.GetNaturalSize();
+
+  DALI_TEST_GREATER( lessThanWidth, static_cast<uint32_t>(naturalSize.width), TEST_LOCATION );
+  DALI_TEST_GREATER( lessThanHeight, static_cast<uint32_t>(naturalSize.height), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTextEditorAtlasLimitationIsEnabledPerformanceCases(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextEditorAtlasLimitationIsEnabledPerformanceCases ");
+
+  // +2: First one to handle the equal case. Second one to handle odd to even case of GetNaturalSize
+  const uint32_t lessThanWidth = TextAbstraction::FontClient::MAX_TEXT_ATLAS_WIDTH - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+  const uint32_t lessThanHeight = TextAbstraction::FontClient::MAX_TEXT_ATLAS_HEIGHT - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+
+  Vector3 naturalSize; //Use GetNaturalSize to verify that size of block does not exceed Atlas size
+  // Create a text editor
+  TextEditor textEditor = TextEditor::New();
+  //Set size to avoid automatic eliding
+  textEditor.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+  textEditor.SetProperty( TextEditor::Property::FONT_FAMILY, "DejaVu Sans");
+  textEditor.SetProperty( TextEditor::Property::TEXT, "A");
+
+  const int numberOfCases = 6;
+  int arrayCases[numberOfCases] = {323, 326, 330, 600, 1630, 2500};
+
+  for (int index=0; index < numberOfCases; index++)
+  {
+    tet_printf(" UtcDaliTextEditorAtlasLimitationIsEnabledPerformanceCases point-size= %d \n", arrayCases[index]);
+    textEditor.SetProperty( TextEditor::Property::POINT_SIZE, arrayCases[index]) ;
+    application.GetScene().Add( textEditor );
+    application.SendNotification();
+    application.Render();
+    naturalSize = textEditor.GetNaturalSize();
+    DALI_TEST_GREATER( lessThanWidth, static_cast<uint32_t>(naturalSize.width), TEST_LOCATION );
+    DALI_TEST_GREATER( lessThanHeight, static_cast<uint32_t>(naturalSize.height), TEST_LOCATION );
+
+  }
+
+  END_TEST;
+}
+
+int UtcDaliTextEditorHyphenWrapMode(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextEditorHyphenWrapMode ");
+
+  int lineCount =0;
+  TextEditor textEditor = TextEditor::New();
+
+  textEditor.SetProperty( Actor::Property::SIZE, Vector2( 150.0f, 300.f ) );
+
+  application.GetScene().Add( textEditor );
+  application.SendNotification();
+  application.Render();
+
+  textEditor.SetProperty( TextEditor::Property::TEXT, "Hi Experimen" );
+  textEditor.SetProperty(TextEditor::Property::LINE_WRAP_MODE, DevelText::LineWrap::HYPHENATION);
+  DALI_TEST_EQUALS( textEditor.GetProperty< int >( TextEditor::Property::LINE_WRAP_MODE ), static_cast< int >( DevelText::LineWrap::HYPHENATION ), TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  lineCount = textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+  /*
+    text will be :
+    Hi Exp-
+    erimen
+  */
+  DALI_TEST_EQUALS( lineCount, 2, TEST_LOCATION );
+
+  textEditor.SetProperty( TextEditor::Property::TEXT, "Hi Experimen" );
+  textEditor.SetProperty(TextEditor::Property::LINE_WRAP_MODE, DevelText::LineWrap::MIXED);
+  DALI_TEST_EQUALS( textEditor.GetProperty< int >( TextEditor::Property::LINE_WRAP_MODE ), static_cast< int >( DevelText::LineWrap::MIXED ), TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  lineCount = textEditor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+  /*
+    text will be :
+    Hi
+    Experi-
+    men
+  */
+  DALI_TEST_EQUALS( lineCount, 3, TEST_LOCATION );
+
+  END_TEST;
 }
\ No newline at end of file
index 05eaeb1..51d27c8 100644 (file)
@@ -1113,7 +1113,7 @@ int utcDaliTextFieldAnchorClicked02(void)
   application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE);
 
   // Create a tap event to touch the text field.
-  TestGenerateTap(application, 30.0f, 25.0f);
+  TestGenerateTap(application, 30.0f, 25.0f, 100);
   application.SendNotification();
   application.Render();
 
@@ -1134,7 +1134,7 @@ int utcDaliTextFieldAnchorClicked02(void)
 
   gAnchorClickedCallBackCalled = false;
   // Create a tap event to touch the text field.
-  TestGenerateTap(application, 30.0f, 25.0f);
+  TestGenerateTap(application, 30.0f, 25.0f, 700);
   application.SendNotification();
   field.SetKeyInputFocus();
 
@@ -1152,7 +1152,7 @@ int utcDaliTextFieldAnchorClicked02(void)
 
   gAnchorClickedCallBackCalled = false;
   // Create a tap event to touch the text field.
-  TestGenerateTap(application, 30.0f, 25.0f);
+  TestGenerateTap(application, 30.0f, 25.0f, 1300);
   application.SendNotification();
   field.SetKeyInputFocus();
 
@@ -1170,7 +1170,7 @@ int utcDaliTextFieldAnchorClicked02(void)
 
   gAnchorClickedCallBackCalled = false;
   // Create a tap event to touch the text field.
-  TestGenerateTap(application, 30.0f, 25.0f);
+  TestGenerateTap(application, 30.0f, 25.0f, 1900);
   application.SendNotification();
   field.SetKeyInputFocus();
 
@@ -1189,7 +1189,7 @@ int utcDaliTextFieldAnchorClicked02(void)
 
   gAnchorClickedCallBackCalled = false;
   // Create a tap event to touch the text field.
-  TestGenerateTap(application, 30.0f, 25.0f);
+  TestGenerateTap(application, 30.0f, 25.0f, 2500);
   application.SendNotification();
   field.SetKeyInputFocus();
 
@@ -1208,7 +1208,7 @@ int utcDaliTextFieldAnchorClicked02(void)
 
   gAnchorClickedCallBackCalled = false;
   // Create a tap event to touch the text field.
-  TestGenerateTap(application, 30.0f, 25.0f);
+  TestGenerateTap(application, 30.0f, 25.0f, 3100);
   application.SendNotification();
   application.Render();
 
@@ -1227,7 +1227,7 @@ int utcDaliTextFieldAnchorClicked02(void)
 
   gAnchorClickedCallBackCalled = false;
   // Create a tap event to touch the text field.
-  TestGenerateTap(application, 30.0f, 25.0f);
+  TestGenerateTap(application, 30.0f, 25.0f, 3700);
   application.SendNotification();
   application.Render();
 
@@ -1246,7 +1246,7 @@ int utcDaliTextFieldAnchorClicked02(void)
 
   gAnchorClickedCallBackCalled = false;
   // Create a tap event to touch the text field.
-  TestGenerateTap(application, 30.0f, 25.0f);
+  TestGenerateTap(application, 30.0f, 25.0f, 4300);
   application.SendNotification();
   application.Render();
 
@@ -1265,7 +1265,7 @@ int utcDaliTextFieldAnchorClicked02(void)
 
   gAnchorClickedCallBackCalled = false;
   // Create a tap event to touch the text field.
-  TestGenerateTap(application, 30.0f, 25.0f);
+  TestGenerateTap(application, 30.0f, 25.0f, 4900);
   application.SendNotification();
   application.Render();
 
@@ -1284,7 +1284,7 @@ int utcDaliTextFieldAnchorClicked02(void)
 
   gAnchorClickedCallBackCalled = false;
   // Create a tap event to touch the text field.
-  TestGenerateTap(application, 30.0f, 25.0f);
+  TestGenerateTap(application, 30.0f, 25.0f, 5500);
   application.SendNotification();
   application.Render();
 
@@ -1931,7 +1931,7 @@ int utcDaliTextFieldInputStyleChanged02(void)
   DALI_TEST_CHECK( !inputStyleChangedSignal );
 
   // Create a tap event to touch the text field.
-  TestGenerateTap( application, 63.0f, 25.0f, 300 );
+  TestGenerateTap( application, 63.0f, 25.0f, 700 );
 
   // Render and notify
   application.SendNotification();
@@ -3555,4 +3555,77 @@ int utcDaliTextFieldMaxCharactersReachedAfterSetText(void)
   DALI_TEST_EQUALS( field.GetProperty( TextField::Property::TEXT ).Get<std::string>(), "123456789", TEST_LOCATION );
 
   END_TEST;
+}
+
+
+
+int UtcDaliTextFieldAtlasLimitationIsEnabledForLargeFontPointSize(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextFieldAtlasLimitationIsEnabledForLargeFontPointSize ");
+
+  // +2: First one to handle the equal case. Second one to handle odd to even case of GetNaturalSize
+  const uint32_t lessThanWidth = TextAbstraction::FontClient::MAX_TEXT_ATLAS_WIDTH - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+  const uint32_t lessThanHeight = TextAbstraction::FontClient::MAX_TEXT_ATLAS_HEIGHT - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+
+  // Create a text field
+  TextField textField = TextField::New();
+
+  //Set size to avoid automatic eliding
+  textField.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+  //Set very large font-size using point-size
+  textField.SetProperty( TextField::Property::POINT_SIZE, 1000) ;
+  //Specify font-family
+  textField.SetProperty( TextField::Property::FONT_FAMILY, "DejaVu Sans");
+  //Set text to check if appear or not
+  textField.SetProperty( TextField::Property::TEXT, "A");
+
+  application.GetScene().Add( textField );
+
+  application.SendNotification();
+  application.Render();
+  //Use GetNaturalSize to verify that size of block does not exceed Atlas size
+  Vector3 naturalSize = textField.GetNaturalSize();
+
+  DALI_TEST_GREATER( lessThanWidth, static_cast<uint32_t>(naturalSize.width), TEST_LOCATION );
+  DALI_TEST_GREATER( lessThanHeight, static_cast<uint32_t>(naturalSize.height), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTextFieldAtlasLimitationIsEnabledPerformanceCases(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextFieldAtlasLimitationIsEnabledPerformanceCases ");
+
+  // +2: First one to handle the equal case. Second one to handle odd to even case of GetNaturalSize
+  const uint32_t lessThanWidth = TextAbstraction::FontClient::MAX_TEXT_ATLAS_WIDTH - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+  const uint32_t lessThanHeight = TextAbstraction::FontClient::MAX_TEXT_ATLAS_HEIGHT - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+
+  Vector3 naturalSize; //Use GetNaturalSize to verify that size of block does not exceed Atlas size
+  // Create a text editor
+  TextField textField = TextField::New();
+
+  //Set size to avoid automatic eliding
+  textField.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+  textField.SetProperty( TextField::Property::FONT_FAMILY, "DejaVu Sans");
+  textField.SetProperty( TextField::Property::TEXT, "A");
+
+  const int numberOfCases = 6;
+  int arrayCases[numberOfCases] = {323, 326, 330, 600, 1630, 2500};
+
+  for (int index=0; index < numberOfCases; index++)
+  {
+    tet_printf(" UtcDaliTextFieldAtlasLimitationIsEnabledPerformanceCases point-size= %d \n", arrayCases[index]);
+    textField.SetProperty( TextField::Property::POINT_SIZE, arrayCases[index]) ;
+    application.GetScene().Add( textField );
+    application.SendNotification();
+    application.Render();
+    naturalSize = textField.GetNaturalSize();
+    DALI_TEST_GREATER( lessThanWidth, static_cast<uint32_t>(naturalSize.width), TEST_LOCATION );
+    DALI_TEST_GREATER( lessThanHeight, static_cast<uint32_t>(naturalSize.height), TEST_LOCATION );
+
+  }
+
+  END_TEST;
 }
\ No newline at end of file
index ecefef7..9a187d6 100644 (file)
@@ -1802,3 +1802,130 @@ int UtcDaliToolkitTextlabelAnchorClicked(void)
 
   END_TEST;
 }
+
+int UtcDaliTextLabelAtlasLimitationIsEnabledForLargeFontPointSize(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLabelAtlasLimitationIsEnabledForLargeFontPointSize ");
+
+  //TextLabel is not using Atlas but this is to unify font-size on text-controllers
+
+  // +2: First one to handle the equal case. Second one to handle odd to even case of GetNaturalSize
+  const uint32_t lessThanWidth = TextAbstraction::FontClient::MAX_TEXT_ATLAS_WIDTH - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+  const uint32_t lessThanHeight = TextAbstraction::FontClient::MAX_TEXT_ATLAS_HEIGHT - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK + 2;
+
+  // Create a text editor
+  TextLabel textLabel = TextLabel::New();
+  //Set size to avoid automatic eliding
+  textLabel.SetProperty( Actor::Property::SIZE, Vector2(1025, 1025));
+  //Set very large font-size using point-size
+  textLabel.SetProperty( TextLabel::Property::POINT_SIZE, 1000);
+  //Specify font-family
+  textLabel.SetProperty( TextLabel::Property::FONT_FAMILY, "DejaVu Sans");
+  //Set text to check if appear or not
+  textLabel.SetProperty( TextLabel::Property::TEXT, "A");
+
+  application.GetScene().Add( textLabel );
+
+  application.SendNotification();
+  application.Render();
+  //Use GetNaturalSize to verify that size of block does not exceed Atlas size
+  Vector3 naturalSize = textLabel.GetNaturalSize();
+
+  DALI_TEST_GREATER( lessThanWidth, static_cast<uint32_t>(naturalSize.width), TEST_LOCATION );
+  DALI_TEST_GREATER( lessThanHeight, static_cast<uint32_t>(naturalSize.height), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTextLabelHyphenWrapMode(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLabelHyphenWrapMode ");
+
+  int lineCount =0;
+  TextLabel label = TextLabel::New();
+  label.SetProperty( Actor::Property::SIZE, Vector2( 150.0f, 300.f ));
+  label.SetProperty( TextLabel::Property::POINT_SIZE, 12.f );
+  label.SetProperty( TextLabel::Property::MULTI_LINE, true);
+  application.GetScene().Add( label );
+  application.SendNotification();
+  application.Render();
+
+  label.SetProperty( TextLabel::Property::TEXT, "Hi Experimen" );
+  label.SetProperty(TextLabel::Property::LINE_WRAP_MODE,DevelText::LineWrap::HYPHENATION);
+  DALI_TEST_EQUALS( label.GetProperty< int >( TextLabel::Property::LINE_WRAP_MODE ), static_cast< int >( DevelText::LineWrap::HYPHENATION ), TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  lineCount = label.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+  /*
+    text will be :
+    Hi Exp-
+    erimen
+  */
+  DALI_TEST_EQUALS( lineCount, 2, TEST_LOCATION );
+
+  label.SetProperty( TextLabel::Property::TEXT, "Hi Experimen" );
+  label.SetProperty(TextLabel::Property::LINE_WRAP_MODE,DevelText::LineWrap::MIXED);
+  DALI_TEST_EQUALS( label.GetProperty< int >( TextLabel::Property::LINE_WRAP_MODE ), static_cast< int >( DevelText::LineWrap::MIXED ), TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  lineCount = label.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+  /*
+    text will be :
+    Hi
+    Experi-
+    men
+  */
+  DALI_TEST_EQUALS( lineCount, 3, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int utcDaliTextLabelGetHeightForWidthChangeLineCountWhenTextChanged(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" utcDaliTextLabelGetHeightForWidthChangeLineCountWhenTextChanged ");
+
+  int lineCountBefore =0 ;
+  int lineCountAfter =0 ;
+
+  // Create a text editor
+  TextLabel textLabel = TextLabel::New();
+  //Set very large font-size using point-size
+  textLabel.SetProperty( TextLabel::Property::POINT_SIZE, 10) ;
+  //Specify font-family
+  textLabel.SetProperty( TextLabel::Property::FONT_FAMILY, "DejaVu Sans");
+  //Specify size
+  textLabel.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 100.f ) );
+  //Set text longer than width of textLabel
+  textLabel.SetProperty( TextLabel::Property::TEXT, "Short text");
+  //Set line wrap mode Character
+  textLabel.SetProperty(TextLabel::Property::LINE_WRAP_MODE, "CHARACTER");
+  textLabel.SetProperty(TextLabel::Property::MULTI_LINE, true);
+
+  application.GetScene().Add( textLabel );
+
+  application.SendNotification();
+  application.Render();
+
+
+  lineCountBefore =  textLabel.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+
+  textLabel.SetProperty( TextLabel::Property::TEXT, "This is very loooooooooooooooooooooooooooooooooooong text for test");
+  lineCountAfter =  textLabel.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+
+  // When the text changed, the Line-count should be updated according to new text.
+  // Because the GetHeightForWidth is called in Controller::GetLineCount(float width)
+  DALI_TEST_EQUALS( lineCountBefore ,1, TEST_LOCATION );
+  DALI_TEST_GREATER( lineCountAfter,1, TEST_LOCATION );
+
+
+  END_TEST;
+}
\ No newline at end of file
index 9a77bba..de842bf 100644 (file)
@@ -458,6 +458,36 @@ int UtcDaliVideoViewMethodsForCoverage2(void)
   END_TEST;
 }
 
+int UtcDaliVideoViewCustomShaderForCoverage3(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 );
+
+  application.GetScene().Add( videoView );
+  videoView.SetProperty( VideoView::Property::VIDEO, "testvideo" );
+
+  Property::Map customShader;
+  customShader.Insert( "vertexShader", VERTEX_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 UtcDaliVideoViewPropertyUnderlay(void)
 {
   ToolkitTestApplication application;
index 127a611..5864554 100644 (file)
@@ -502,6 +502,9 @@ int UtcDaliVisualGetPropertyMap1(void)
   propertyMap.Insert(Visual::Property::MIX_COLOR,  Color::BLUE);
   propertyMap.Insert( DevelVisual::Property::CORNER_RADIUS, 10.0f );
   propertyMap.Insert( DevelVisual::Property::CORNER_RADIUS_POLICY, Toolkit::Visual::Transform::Policy::RELATIVE );
+  propertyMap.Insert( DevelVisual::Property::BORDERLINE_WIDTH, 20.0f );
+  propertyMap.Insert( DevelVisual::Property::BORDERLINE_COLOR, Color::RED );
+  propertyMap.Insert( DevelVisual::Property::BORDERLINE_OFFSET, -1.0f );
   propertyMap.Insert( DevelColorVisual::Property::BLUR_RADIUS, 20.0f );
   Visual::Base colorVisual = factory.CreateVisual( propertyMap );
 
@@ -524,6 +527,18 @@ int UtcDaliVisualGetPropertyMap1(void)
   DALI_TEST_CHECK( cornerRadiusPolicyValue );
   DALI_TEST_CHECK( cornerRadiusPolicyValue->Get< int >() == Toolkit::Visual::Transform::Policy::RELATIVE );
 
+  Property::Value* borderlineWidthValue = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT );
+  DALI_TEST_CHECK( borderlineWidthValue );
+  DALI_TEST_CHECK( borderlineWidthValue->Get< float >() == 20.0f );
+
+  Property::Value* borderlineColorValue = resultMap.Find( DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4 );
+  DALI_TEST_CHECK( borderlineColorValue );
+  DALI_TEST_CHECK( borderlineColorValue->Get< Vector4 >() == Color::RED );
+
+  Property::Value* borderlineOffsetValue = resultMap.Find( DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT );
+  DALI_TEST_CHECK( borderlineOffsetValue );
+  DALI_TEST_CHECK( borderlineOffsetValue->Get< float >() == -1.0f );
+
   Property::Value* blurRadiusValue = resultMap.Find( DevelColorVisual::Property::BLUR_RADIUS, Property::FLOAT );
   DALI_TEST_CHECK( blurRadiusValue );
   DALI_TEST_CHECK( blurRadiusValue->Get< float >() == 20.0f );
@@ -599,10 +614,23 @@ int UtcDaliVisualGetPropertyMap2(void)
   DALI_TEST_CHECK( colorValue );
   DALI_TEST_CHECK( colorValue->Get<Vector4>() == Color::CYAN );
 
-  colorValue = resultMap.Find( BorderVisual::Property::SIZE,  Property::FLOAT );
+  sizeValue = resultMap.Find( BorderVisual::Property::SIZE,  Property::FLOAT );
+  DALI_TEST_CHECK( sizeValue );
+  DALI_TEST_CHECK( sizeValue->Get<float>() == 10.f );
+
+  // Get default value of borderline values here
+
+  sizeValue = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH,  Property::FLOAT );
+  DALI_TEST_CHECK( sizeValue );
+  DALI_TEST_CHECK( sizeValue->Get<float>() == 0.0f );
+
+  colorValue = resultMap.Find( DevelVisual::Property::BORDERLINE_COLOR,  Property::VECTOR4 );
   DALI_TEST_CHECK( colorValue );
-  DALI_TEST_CHECK( colorValue->Get<float>() == 10.f );
+  DALI_TEST_CHECK( colorValue->Get<Vector4>() == Color::BLACK );
 
+  sizeValue = resultMap.Find( DevelVisual::Property::BORDERLINE_OFFSET,  Property::FLOAT );
+  DALI_TEST_CHECK( sizeValue );
+  DALI_TEST_CHECK( sizeValue->Get<float>() == 0.0f );
 
   END_TEST;
 }
@@ -655,6 +683,11 @@ int UtcDaliVisualGetPropertyMap3(void)
   stopColors.PushBack( Color::GREEN );
   propertyMap.Insert(GradientVisual::Property::STOP_COLOR,   stopColors);
 
+  float borderlineWidth = 4.0f;
+  Vector4 cornerRadius(7.0f, 10.0f, 13.0f, 16.0f);
+  propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH,  borderlineWidth);
+  propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS,  cornerRadius);
+
   Visual::Base gradientVisual = factory.CreateVisual(propertyMap);
 
   Property::Map resultMap;
@@ -681,6 +714,14 @@ int UtcDaliVisualGetPropertyMap3(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_EQUALS( value->Get<Vector2>(), end , Math::MACHINE_EPSILON_100, TEST_LOCATION );
 
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH,   Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), borderlineWidth , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( DevelVisual::Property::CORNER_RADIUS,   Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), cornerRadius , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
   value = resultMap.Find( GradientVisual::Property::STOP_OFFSET,   Property::ARRAY );
   DALI_TEST_CHECK( value );
   Property::Array* offsetArray = value->GetArray();
@@ -722,6 +763,11 @@ int UtcDaliVisualGetPropertyMap4(void)
   stopColors.PushBack( Color::GREEN );
   propertyMap.Insert(GradientVisual::Property::STOP_COLOR,   stopColors);
 
+  float borderlineWidth = 8.0f;
+  Vector4 cornerRadius(1.0f, 2.0f, 4.0f, 8.0f);
+  propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH,  borderlineWidth);
+  propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS,  cornerRadius);
+
   Visual::Base gradientVisual = factory.CreateVisual(propertyMap);
   DALI_TEST_CHECK( gradientVisual );
 
@@ -749,6 +795,14 @@ int UtcDaliVisualGetPropertyMap4(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_EQUALS( value->Get<float>(), radius , Math::MACHINE_EPSILON_100, TEST_LOCATION );
 
+  value = resultMap.Find( DevelVisual::Property::BORDERLINE_WIDTH,   Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), borderlineWidth , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( DevelVisual::Property::CORNER_RADIUS,   Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), cornerRadius , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
   value = resultMap.Find( GradientVisual::Property::STOP_OFFSET,   Property::ARRAY );
   DALI_TEST_CHECK( value );
   Property::Array* offsetArray = value->GetArray();
@@ -3559,56 +3613,6 @@ int UtcDaliRegisterVisualWithDepthIndex(void)
   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;
@@ -3960,6 +3964,361 @@ int UtcDaliVisualRoundedCorner(void)
   END_TEST;
 }
 
+int UtcDaliVisualBorderline(void)
+{
+#ifdef OLD_GRAPHICS_TEST
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualBorderline" );
+
+  static std::vector<UniformData> customUniforms =
+  {
+    UniformData("cornerRadius", Property::Type::VECTOR4),
+    UniformData("cornerRadiusPolicy", Property::Type::FLOAT),
+    UniformData("borderlineWidth", Property::Type::FLOAT),
+    UniformData("borderlineColor", Property::Type::VECTOR4),
+    UniformData("borderlineOffset", Property::Type::FLOAT),
+  };
+
+  TestGraphicsController& graphics = application.GetGraphicsController();
+  graphics.AddCustomUniforms(customUniforms);
+
+  // image visual
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    float cornerRadius = 5.0f;
+    float borderlineWidth = 30.0f;
+    Vector4 borderlineColor(1.0f, 0.0f, 0.0f, 1.0f);
+    float borderlineOffset = 1.0f;
+
+    properties[Visual::Property::TYPE] = Visual::IMAGE;
+    properties[ImageVisual::Property::URL] = TEST_IMAGE_FILE_NAME;
+    properties[DevelVisual::Property::CORNER_RADIUS] = cornerRadius;
+    properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+    properties[DevelVisual::Property::BORDERLINE_COLOR] = borderlineColor;
+    properties[DevelVisual::Property::BORDERLINE_OFFSET] = borderlineOffset;
+
+    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.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+    dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+    application.GetScene().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< Vector4 >( "cornerRadius", Vector4(cornerRadius, cornerRadius, cornerRadius, cornerRadius) ), true, TEST_LOCATION );
+    // Default corner radius policy is absolute.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "cornerRadiusPolicy", Toolkit::Visual::Transform::Policy::ABSOLUTE ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", borderlineColor ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", borderlineOffset ), true, TEST_LOCATION );
+  }
+
+  // color visual 1
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    Vector4 cornerRadius(23.0f, 2.0f, 3.0f, 2.3f);
+    float borderlineWidth = 30.0f;
+    Vector4 borderlineColor(0.5f, 0.4f, 0.3f, 0.2f);
+    float borderlineOffset = -0.4f;
+
+    properties[Visual::Property::TYPE] = Visual::COLOR;
+    properties[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+    properties["cornerRadius"] = cornerRadius;
+    properties["borderlineWidth"] = borderlineWidth;
+    properties["borderlineColor"] = borderlineColor;
+    properties["borderlineOffset"] = borderlineOffset;
+
+    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.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+    dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+    application.GetScene().Add( dummy );
+
+    application.SendNotification();
+    application.Render();
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "cornerRadius", cornerRadius ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", borderlineColor ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", borderlineOffset ), true, TEST_LOCATION );
+  }
+
+  // color visual 2, default color, default offset
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    float borderlineWidth = 30.0f;
+
+    properties[Visual::Property::TYPE] = Visual::COLOR;
+    properties[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+    properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+
+    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.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+    dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+    application.GetScene().Add( dummy );
+
+    application.SendNotification();
+    application.Render();
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+    // Default borderline color is BLACK.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", Color::BLACK ), true, TEST_LOCATION );
+    // Default borderline offset is 0.0f.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", 0.0f ), true, TEST_LOCATION );
+  }
+
+  // color visual 3, offset not [-1.0 ~ 1.0], but uniform value is same anyway
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    float borderlineWidth = 30.0f;
+    Vector4 borderlineColor(0.5f, 0.4f, 0.3f, 0.2f);
+    float borderlineOffset = 37.4f;
+
+    properties[Visual::Property::TYPE] = Visual::COLOR;
+    properties[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+    properties["borderlineWidth"] = borderlineWidth;
+    properties["borderlineColor"] = borderlineColor;
+    properties["borderlineOffset"] = borderlineOffset;
+
+    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.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+    dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+    application.GetScene().Add( dummy );
+
+    application.SendNotification();
+    application.Render();
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", borderlineColor ), true, TEST_LOCATION );
+    // NOTE : borderlineOffset will clamp in fragment shader. not visual itself
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", borderlineOffset ), true, TEST_LOCATION );
+  }
+
+  // gradient visual
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    float borderlineWidth = 30.0f;
+    float cornerRadius = 70.0f;
+
+    properties[Visual::Property::TYPE] = Visual::GRADIENT;
+    properties[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+    properties[DevelVisual::Property::CORNER_RADIUS] = cornerRadius;
+    properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+    properties[GradientVisual::Property::START_POSITION] = Vector2( 0.5f, 0.5f );
+    properties[GradientVisual::Property::END_POSITION] = Vector2( -0.5f, -0.5f );
+    properties[GradientVisual::Property::UNITS] = GradientVisual::Units::USER_SPACE;
+
+    Property::Array stopOffsets;
+    stopOffsets.PushBack( 0.0f );
+    stopOffsets.PushBack( 0.6f );
+    stopOffsets.PushBack( 1.0f );
+    properties[GradientVisual::Property::STOP_OFFSET] = stopOffsets;
+
+    Property::Array stopColors;
+    stopColors.PushBack( Color::RED );
+    stopColors.PushBack( Color::YELLOW );
+    stopColors.PushBack( Color::GREEN );
+    properties[GradientVisual::Property::STOP_COLOR] = stopColors;
+
+    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.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+    dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+    application.GetScene().Add( dummy );
+
+    application.SendNotification();
+    application.Render();
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "cornerRadius", Vector4(cornerRadius, cornerRadius, cornerRadius, cornerRadius) ), true, TEST_LOCATION );
+    // Default corner radius policy is absolute.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "cornerRadiusPolicy", Toolkit::Visual::Transform::Policy::ABSOLUTE ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+    // Default borderline color is BLACK.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", Color::BLACK ), true, TEST_LOCATION );
+    // Default borderline offset is 0.0f.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", 0.0f ), true, TEST_LOCATION );
+  }
+
+  // animated image visual
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    float borderlineWidth = 24.0f;
+    float borderlineOffset = -1.0f;
+
+    properties[Visual::Property::TYPE] = Visual::ANIMATED_IMAGE;
+    properties[ImageVisual::Property::URL] = TEST_GIF_FILE_NAME;
+    properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth + 10.0f; // Dummy Input
+    properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+    properties["borderlineOffset"] = borderlineOffset;
+
+    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.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+    dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+    application.GetScene().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 >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+    // Default borderline color is BLACK.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", Color::BLACK ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", borderlineOffset ), true, TEST_LOCATION );
+  }
+
+  // vector image visual
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    Vector4 cornerRadius(54.0f, 43.0f, 32.0f, 21.0f);
+    float borderlineWidth = 27.0f;
+    Vector4 borderlineColor(0.5f, 0.5f, 0.5f, 0.0f);
+
+    properties[Visual::Property::TYPE] = Visual::SVG;
+    properties[ImageVisual::Property::URL] = TEST_SVG_FILE_NAME;
+    properties[DevelVisual::Property::CORNER_RADIUS] = cornerRadius;
+    properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+    properties[DevelVisual::Property::BORDERLINE_COLOR] = borderlineColor;
+
+    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.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+    dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+    application.GetScene().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< Vector4 >( "cornerRadius", cornerRadius ), true, TEST_LOCATION );
+    // Default corner radius policy is absolute.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "cornerRadiusPolicy", Toolkit::Visual::Transform::Policy::ABSOLUTE ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", borderlineColor ), true, TEST_LOCATION );
+    // Default borderline offset is 0.0.
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", 0.0f ), true, TEST_LOCATION );
+  }
+
+  // animated vector image visual
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    Vector4 cornerRadius(1.3f, 0.0f, 0.4f, 0.2f);
+    float borderlineWidth = 13.0f;
+    Vector4 borderlineColor(0.3f, 0.3f, 0.3f, 1.0f);
+    float borderlineOffset = 13.0f;
+
+    properties[Visual::Property::TYPE] = DevelVisual::ANIMATED_VECTOR_IMAGE;
+    properties[ImageVisual::Property::URL] = TEST_VECTOR_IMAGE_FILE_NAME;
+    properties["cornerRadius"] = cornerRadius;
+    properties[DevelVisual::Property::CORNER_RADIUS_POLICY] = Toolkit::Visual::Transform::Policy::RELATIVE;
+    properties[DevelVisual::Property::BORDERLINE_WIDTH] = borderlineWidth;
+    properties["borderlineColor"] = borderlineColor;
+    properties[DevelVisual::Property::BORDERLINE_OFFSET] = borderlineOffset;
+
+    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.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) );
+    dummy.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+    application.GetScene().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< Vector4 >( "cornerRadius", cornerRadius ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "cornerRadiusPolicy", Toolkit::Visual::Transform::Policy::RELATIVE ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineWidth", borderlineWidth ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< Vector4 >( "borderlineColor", borderlineColor ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "borderlineOffset", borderlineOffset ), true, TEST_LOCATION );
+  }
+#else
+  tet_result(TET_PASS);
+#endif
+
+  END_TEST;
+}
+
+
 int UtcDaliColorVisualBlurRadius(void)
 {
   ToolkitTestApplication application;
@@ -4151,6 +4510,9 @@ int UtcDaliVisualGetVisualProperty01(void)
     UniformData("size", Property::Type::VECTOR2),
     UniformData("cornerRadius", Property::Type::VECTOR4),
     UniformData("blurRadius", Property::Type::FLOAT),
+    UniformData("borderlineWidth", Property::Type::FLOAT),
+    UniformData("borderlineColor", Property::Type::VECTOR4),
+    UniformData("borderlineOffset", Property::Type::FLOAT),
   };
 
   TestGraphicsController& graphics = application.GetGraphicsController();
@@ -4163,6 +4525,9 @@ int UtcDaliVisualGetVisualProperty01(void)
   propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS, Vector4(10.0f, 0.0f, 2.0f, 4.0f));
   propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS_POLICY, Toolkit::Visual::Transform::Policy::RELATIVE);
   propertyMap.Insert(DevelColorVisual::Property::BLUR_RADIUS, 20.0f);
+  propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH, 20.0f);
+  propertyMap.Insert(DevelVisual::Property::BORDERLINE_COLOR, Color::RED);
+  propertyMap.Insert(DevelVisual::Property::BORDERLINE_OFFSET, 1.0f);
   Visual::Base colorVisual = factory.CreateVisual(propertyMap);
 
   DummyControl dummyControl = DummyControl::New(true);
@@ -4180,6 +4545,9 @@ int UtcDaliVisualGetVisualProperty01(void)
   float targetOpacity = 0.5f;
   Vector4 targetCornerRadius(0.0f, 0.0f, 0.0f, 0.0f);
   float targetBlurRadius = 10.0f;
+  float targetBorderlineWidth = 25.0f;
+  Vector4 targetBorderlineColor(1.0f, 1.0f, 1.0f, 1.0f);
+  float targetBorderlineOffset = -1.0f;
 
   Animation animation = Animation::New(1.0f);
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, Visual::Property::MIX_COLOR), targetColor);
@@ -4188,6 +4556,9 @@ int UtcDaliVisualGetVisualProperty01(void)
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, Visual::Transform::Property::SIZE), targetSize);
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::CORNER_RADIUS), targetCornerRadius);
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelColorVisual::Property::BLUR_RADIUS), targetBlurRadius);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_WIDTH), targetBorderlineWidth);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_COLOR), targetBorderlineColor);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_OFFSET), targetBorderlineOffset);
   animation.Play();
 
   application.SendNotification();
@@ -4222,23 +4593,33 @@ int UtcDaliVisualGetVisualProperty01(void)
   DALI_TEST_CHECK(blurRadiusValue);
   DALI_TEST_EQUALS(blurRadiusValue->Get< float >(), targetBlurRadius, TEST_LOCATION);
 
+  Property::Value* borderlineWidthValue = resultMap.Find(DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT);
+  DALI_TEST_CHECK(borderlineWidthValue);
+  DALI_TEST_EQUALS(borderlineWidthValue->Get< float >(), targetBorderlineWidth, TEST_LOCATION);
+
+  Property::Value* borderlineColorValue = resultMap.Find(DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4);
+  DALI_TEST_CHECK(borderlineColorValue);
+  DALI_TEST_EQUALS(borderlineColorValue->Get< Vector4 >(), targetBorderlineColor, TEST_LOCATION);
+
+  Property::Value* borderlineOffsetValue = resultMap.Find(DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT);
+  DALI_TEST_CHECK(borderlineOffsetValue);
+  DALI_TEST_EQUALS(borderlineOffsetValue->Get< float >(), targetBorderlineOffset, TEST_LOCATION);
+
   // Test uniform values
   DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector3>("mixColor", targetColor), true, TEST_LOCATION);
   DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector2>("offset", targetOffset), true, TEST_LOCATION);
   DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector2>("size", targetSize), true, TEST_LOCATION);
   DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector4>("cornerRadius", targetCornerRadius), true, TEST_LOCATION);
   DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<float>("blurRadius", targetBlurRadius), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<float>("borderlineWidth", targetBorderlineWidth), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector4>("borderlineColor", targetBorderlineColor), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<float>("borderlineOffset", targetBorderlineOffset), true, TEST_LOCATION);
 
   // Test not-supported property
   Property property1 = DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, Visual::Property::PREMULTIPLIED_ALPHA);
   DALI_TEST_CHECK(!property1.object);
   DALI_TEST_CHECK(property1.propertyIndex == Property::INVALID_INDEX);
 
-  // Test not-supported property
-  Property property2 = DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelColorVisual::Property::RENDER_IF_TRANSPARENT);
-  DALI_TEST_CHECK(!property2.object);
-  DALI_TEST_CHECK(property2.propertyIndex == Property::INVALID_INDEX);
-
   // Test unregistered visual
   Property property3 = DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL2, Visual::Property::MIX_COLOR);
   DALI_TEST_CHECK(!property3.object);
@@ -4258,6 +4639,9 @@ int UtcDaliVisualGetVisualProperty02(void)
     UniformData("offset", Property::Type::VECTOR2),
     UniformData("size", Property::Type::VECTOR2),
     UniformData("cornerRadius", Property::Type::VECTOR4),
+    UniformData("borderlineWidth", Property::Type::FLOAT),
+    UniformData("borderlineCOlor", Property::Type::VECTOR4),
+    UniformData("borderlineOffset", Property::Type::FLOAT),
     UniformData("blurRadius", Property::Type::FLOAT),
   };
 
@@ -4283,6 +4667,9 @@ int UtcDaliVisualGetVisualProperty02(void)
   Vector2 targetSize(1.1f, 1.1f);
   float targetOpacity = 0.5f;
   Vector4 targetCornerRadius(20.0f, 0.0f, 20.0f, 0.0f);
+  float targetBorderlineWidth = 77.7f;
+  Vector4 targetBorderlineColor(0.4f, 0.2f, 0.3f, 0.9f);
+  float targetBorderlineOffset = 1.0f;
   float targetBlurRadius = 10.0f;
 
   // Should work when the properties are not set before
@@ -4292,6 +4679,9 @@ int UtcDaliVisualGetVisualProperty02(void)
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "offset"), targetOffset);
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "size"), targetSize);
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "cornerRadius"), targetCornerRadius);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "borderlineWidth"), targetBorderlineWidth);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "borderlineColor"), targetBorderlineColor);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "borderlineOffset"), targetBorderlineOffset);
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, "blurRadius"), targetBlurRadius);
   animation.Play();
 
@@ -4323,6 +4713,18 @@ int UtcDaliVisualGetVisualProperty02(void)
   DALI_TEST_CHECK(cornerRadiusValue);
   DALI_TEST_EQUALS(cornerRadiusValue->Get< Vector4 >(), targetCornerRadius, TEST_LOCATION);
 
+  Property::Value* borderlineWidthValue = resultMap.Find(DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT);
+  DALI_TEST_CHECK(borderlineWidthValue);
+  DALI_TEST_EQUALS(borderlineWidthValue->Get< float >(), targetBorderlineWidth, TEST_LOCATION);
+
+  Property::Value* borderlineColorValue = resultMap.Find(DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4);
+  DALI_TEST_CHECK(borderlineColorValue);
+  DALI_TEST_EQUALS(borderlineColorValue->Get< Vector4 >(), targetBorderlineColor, TEST_LOCATION);
+
+  Property::Value* borderlineOffsetValue = resultMap.Find(DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT);
+  DALI_TEST_CHECK(borderlineOffsetValue);
+  DALI_TEST_EQUALS(borderlineOffsetValue->Get< float >(), targetBorderlineOffset, TEST_LOCATION);
+
   Property::Value* blurRadiusValue = resultMap.Find(DevelColorVisual::Property::BLUR_RADIUS, Property::FLOAT);
   DALI_TEST_CHECK(blurRadiusValue);
   DALI_TEST_EQUALS(blurRadiusValue->Get< float >(), targetBlurRadius, TEST_LOCATION);
@@ -4343,11 +4745,14 @@ int UtcDaliVisualGetVisualProperty03(void)
 {
 #ifdef OLD_GRAPHICS_TEST
   ToolkitTestApplication application;
-  tet_infoline( "UtcDaliVisualGetVisualProperty01: Test animatable property, ImageVisual" );
+  tet_infoline( "UtcDaliVisualGetVisualProperty03: Test animatable property, ImageVisual" );
 
   static std::vector<UniformData> customUniforms =
   {
     UniformData("cornerRadius", Property::Type::VECTOR4),
+    UniformData("borderlineWidth", Property::Type::FLOAT),
+    UniformData("borderlineColor", Property::Type::VECTOR4),
+    UniformData("borderlineOffset", Property::Type::FLOAT),
   };
 
   TestGraphicsController& graphics = application.GetGraphicsController();
@@ -4357,6 +4762,10 @@ int UtcDaliVisualGetVisualProperty03(void)
   Property::Map propertyMap;
   propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE);
   propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME);
+  //We must set some value because application cannot notify shader changed
+  propertyMap.Insert(DevelVisual::Property::CORNER_RADIUS, 1.0f);
+  propertyMap.Insert(DevelVisual::Property::BORDERLINE_WIDTH, 1.0f);
+
   Visual::Base imageVisual = factory.CreateVisual(propertyMap);
 
   DummyControl dummyControl = DummyControl::New(true);
@@ -4373,10 +4782,16 @@ int UtcDaliVisualGetVisualProperty03(void)
 
   float targetOpacity = 0.5f;
   Vector4 targetCornerRadius(20.0f, 20.0f, 0.0f, 0.0f);
+  float targetBorderlineWidth = 10.0f;
+  Vector4 targetBorderlineColor(1.0f, 0.0f, 1.0f, 0.5f);
+  float targetBorderlineOffset = -1.5f;
 
   Animation animation = Animation::New(1.0f);
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, Visual::Property::OPACITY), targetOpacity);
   animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::CORNER_RADIUS), targetCornerRadius);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_WIDTH), targetBorderlineWidth);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_COLOR), targetBorderlineColor);
+  animation.AnimateTo(DevelControl::GetVisualProperty(dummyControl, DummyControl::Property::TEST_VISUAL, DevelVisual::Property::BORDERLINE_OFFSET), targetBorderlineOffset);
   animation.Play();
 
   application.SendNotification();
@@ -4395,8 +4810,23 @@ int UtcDaliVisualGetVisualProperty03(void)
   DALI_TEST_CHECK(cornerRadiusValue);
   DALI_TEST_EQUALS(cornerRadiusValue->Get< Vector4 >(), targetCornerRadius, TEST_LOCATION);
 
+  Property::Value* borderlineWidthValue = resultMap.Find(DevelVisual::Property::BORDERLINE_WIDTH, Property::FLOAT);
+  DALI_TEST_CHECK(borderlineWidthValue);
+  DALI_TEST_EQUALS(borderlineWidthValue->Get< float >(), targetBorderlineWidth, TEST_LOCATION);
+
+  Property::Value* borderlineColorValue = resultMap.Find(DevelVisual::Property::BORDERLINE_COLOR, Property::VECTOR4);
+  DALI_TEST_CHECK(borderlineColorValue);
+  DALI_TEST_EQUALS(borderlineColorValue->Get< Vector4 >(), targetBorderlineColor, TEST_LOCATION);
+
+  Property::Value* borderlineOffsetValue = resultMap.Find(DevelVisual::Property::BORDERLINE_OFFSET, Property::FLOAT);
+  DALI_TEST_CHECK(borderlineOffsetValue);
+  DALI_TEST_EQUALS(borderlineOffsetValue->Get< float >(), targetBorderlineOffset, TEST_LOCATION);
+
   // Test uniform value
   DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector4>("cornerRadius", targetCornerRadius), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<float>("borderlineWidth", targetBorderlineWidth), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<Vector4>("borderlineColor", targetBorderlineColor), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(application.GetGlAbstraction().CheckUniformValue<float>("borderlineOffset", targetBorderlineOffset), true, TEST_LOCATION);
 #else
   tet_result(TET_PASS);
 #endif
index 86776ff..4fbe8c1 100755 (executable)
@@ -81,8 +81,8 @@ static int gRequestInterceptorCallbackCalled = 0;
 static std::shared_ptr<Dali::WebEngineRequestInterceptor> gRequestInterceptorInstance = nullptr;
 static int gConsoleMessageCallbackCalled = 0;
 static std::shared_ptr<Dali::WebEngineConsoleMessage> gConsoleMessageInstance = nullptr;
-static int gPolicyDecisionCallbackCalled = 0;
-static std::shared_ptr<Dali::WebEnginePolicyDecision> gPolicyDecisionInstance = nullptr;
+static int gResponsePolicyDecidedCallbackCalled = 0;
+static std::shared_ptr<Dali::WebEnginePolicyDecision> gResponsePolicyDecisionInstance = nullptr;
 static int gCertificateConfirmCallbackCalled = 0;
 static std::shared_ptr<Dali::WebEngineCertificate> gCertificateConfirmInstance = nullptr;
 static int gSslCertificateChangedCallbackCalled = 0;
@@ -137,10 +137,10 @@ static void OnScrollEdgeReached( WebView view, Dali::WebEnginePlugin::ScrollEdge
   gScrollEdgeReachedCallbackCalled++;
 }
 
-static void OnPolicyDecisionRequest(WebView view, std::shared_ptr<Dali::WebEnginePolicyDecision> decision)
+static void OnResponsePolicyDecided(WebView view, std::shared_ptr<Dali::WebEnginePolicyDecision> decision)
 {
-  gPolicyDecisionCallbackCalled++;
-  gPolicyDecisionInstance = std::move(decision);
+  gResponsePolicyDecidedCallbackCalled++;
+  gResponsePolicyDecisionInstance = std::move(decision);
 }
 
 static void OnUrlChanged( WebView view, const std::string& url )
@@ -1059,12 +1059,16 @@ int UtcDaliWebViewPropertyTitleFavicon(void)
   view.GetProperty( WebView::Property::TITLE ).Get( output );
   DALI_TEST_EQUALS( output, testValue, TEST_LOCATION );
 
-  // Check default value of favicon
-  Dali::Toolkit::ImageView* favicon = &view.GetFavicon();
+  // Check the case that favicon is not null.
+  Dali::Toolkit::ImageView favicon = view.GetFavicon();
   DALI_TEST_CHECK( favicon );
-  Dali::Vector3 iconsize = favicon->GetProperty< Vector3 >( Dali::Actor::Property::SIZE );
+  Dali::Vector3 iconsize = favicon.GetProperty< Vector3 >( Dali::Actor::Property::SIZE );
   DALI_TEST_CHECK( ( int )iconsize.width == 2 && ( int )iconsize.height == 2 );
 
+  // Check the case that favicon is null.
+  favicon = view.GetFavicon();
+  DALI_TEST_CHECK( !favicon );
+
   END_TEST;
 }
 
@@ -1300,7 +1304,7 @@ int UtcDaliWebViewHttpRequestInterceptor(void)
   END_TEST;
 }
 
-int UtcDaliWebViewPolicyDecisionRequest(void)
+int UtcDaliWebViewResponsePolicyDecisionRequest(void)
 {
   ToolkitTestApplication application;
 
@@ -1309,42 +1313,42 @@ int UtcDaliWebViewPolicyDecisionRequest(void)
 
   // load url.
   ConnectionTracker* testTracker = new ConnectionTracker();
-  view.PolicyDecisionSignal().Connect( &OnPolicyDecisionRequest );
+  view.ResponsePolicyDecisionSignal().Connect( &OnResponsePolicyDecided );
   bool signal1 = false;
-  view.ConnectSignal( testTracker, "policyDecision", CallbackFunctor(&signal1) );
-  DALI_TEST_EQUALS( gPolicyDecisionCallbackCalled, 0, TEST_LOCATION );
-  DALI_TEST_CHECK(gPolicyDecisionInstance == 0);
+  view.ConnectSignal( testTracker, "responsePolicyDecided", CallbackFunctor(&signal1) );
+  DALI_TEST_EQUALS( gResponsePolicyDecidedCallbackCalled, 0, TEST_LOCATION );
+  DALI_TEST_CHECK(gResponsePolicyDecisionInstance == 0);
 
   view.LoadUrl( TEST_URL1 );
   Test::EmitGlobalTimerSignal();
-  DALI_TEST_EQUALS( gPolicyDecisionCallbackCalled, 1, TEST_LOCATION );
+  DALI_TEST_EQUALS( gResponsePolicyDecidedCallbackCalled, 1, TEST_LOCATION );
   DALI_TEST_CHECK( signal1 );
 
-  // check policy decision & its frame.
-  DALI_TEST_CHECK(gPolicyDecisionInstance != 0);
+  // check response policy decision & its frame.
+  DALI_TEST_CHECK(gResponsePolicyDecisionInstance != 0);
   std::string testUrl("http://test.html");
-  DALI_TEST_EQUALS(gPolicyDecisionInstance->GetUrl(), testUrl, TEST_LOCATION);
+  DALI_TEST_EQUALS(gResponsePolicyDecisionInstance->GetUrl(), testUrl, TEST_LOCATION);
   std::string testCookie("test:abc");
-  DALI_TEST_EQUALS(gPolicyDecisionInstance->GetCookie(), testCookie, TEST_LOCATION);
+  DALI_TEST_EQUALS(gResponsePolicyDecisionInstance->GetCookie(), testCookie, TEST_LOCATION);
   Dali::WebEnginePolicyDecision::DecisionType testDecisionType = Dali::WebEnginePolicyDecision::DecisionType::USE;
-  DALI_TEST_EQUALS(gPolicyDecisionInstance->GetDecisionType(), testDecisionType, TEST_LOCATION);
+  DALI_TEST_EQUALS(gResponsePolicyDecisionInstance->GetDecisionType(), testDecisionType, TEST_LOCATION);
   std::string testResponseMime("txt/xml");
-  DALI_TEST_EQUALS(gPolicyDecisionInstance->GetResponseMime(), testResponseMime, TEST_LOCATION);
+  DALI_TEST_EQUALS(gResponsePolicyDecisionInstance->GetResponseMime(), testResponseMime, TEST_LOCATION);
   int32_t ResponseStatusCode = 500;
-  DALI_TEST_EQUALS(gPolicyDecisionInstance->GetResponseStatusCode(), ResponseStatusCode, TEST_LOCATION);
+  DALI_TEST_EQUALS(gResponsePolicyDecisionInstance->GetResponseStatusCode(), ResponseStatusCode, TEST_LOCATION);
   Dali::WebEnginePolicyDecision::NavigationType testNavigationType = Dali::WebEnginePolicyDecision::NavigationType::LINK_CLICKED;
-  DALI_TEST_EQUALS(gPolicyDecisionInstance->GetNavigationType(), testNavigationType, TEST_LOCATION);
+  DALI_TEST_EQUALS(gResponsePolicyDecisionInstance->GetNavigationType(), testNavigationType, TEST_LOCATION);
   std::string testScheme("test");
-  DALI_TEST_EQUALS(gPolicyDecisionInstance->GetScheme(), testScheme, TEST_LOCATION);
-  DALI_TEST_CHECK(gPolicyDecisionInstance->Use());
-  DALI_TEST_CHECK(gPolicyDecisionInstance->Ignore());
-  DALI_TEST_CHECK(gPolicyDecisionInstance->Suspend());
+  DALI_TEST_EQUALS(gResponsePolicyDecisionInstance->GetScheme(), testScheme, TEST_LOCATION);
+  DALI_TEST_CHECK(gResponsePolicyDecisionInstance->Use());
+  DALI_TEST_CHECK(gResponsePolicyDecisionInstance->Ignore());
+  DALI_TEST_CHECK(gResponsePolicyDecisionInstance->Suspend());
 
-  Dali::WebEngineFrame* webFrame = &(gPolicyDecisionInstance->GetFrame());
+  Dali::WebEngineFrame* webFrame = &(gResponsePolicyDecisionInstance->GetFrame());
   DALI_TEST_CHECK(webFrame);
   DALI_TEST_CHECK(webFrame->IsMainFrame());
 
-  gPolicyDecisionInstance = nullptr;
+  gResponsePolicyDecisionInstance = nullptr;
 
   END_TEST;
 }
index 906453d..2258fab 100644 (file)
@@ -295,13 +295,25 @@ SET_PROPERTY(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
 SET(SHADER_GENERATOR_NAME dali-shader-generator)
 SET(SHADER_GENERATOR_SOURCES ${ROOT_SRC_DIR}/dali-toolkit/shader-generator/shader-generator.cpp)
 
+IF( WIN32)
+  # When Using VCPKG, the default is always set to Debug if CMAKE_BUILD_TYPE is not set
+  IF( NOT CMAKE_BUILD_TYPE )
+    SET(SHADER_GENERATOR_BINARY ${CMAKE_CURRENT_BINARY_DIR}/Debug/${SHADER_GENERATOR_NAME})
+  ELSE()
+    SET(SHADER_GENERATOR_BINARY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${SHADER_GENERATOR_NAME})
+  ENDIF()
+ELSE()
+  SET(SHADER_GENERATOR_BINARY ${CMAKE_CURRENT_BINARY_DIR}/${SHADER_GENERATOR_NAME})
+ENDIF()
+
 IF(NOT ANDROID)
   ADD_EXECUTABLE(${SHADER_GENERATOR_NAME} ${SHADER_GENERATOR_SOURCES})
-  INSTALL(TARGETS ${SHADER_GENERATOR_NAME} DESTINATION ${BINDIR})
+  TARGET_LINK_LIBRARIES( ${SHADER_GENERATOR_NAME} ${COVERAGE} )
+  INSTALL(TARGETS ${SHADER_GENERATOR_NAME} RUNTIME DESTINATION bin)
 ELSE()
   # Need to build dali-shader-generator using the host compiler, not the android cross-compiler so
   # that it can be run on the host machine
-  OPTION(ANDROID_HOST_COMPILER "Provide the host compiler used by Android (Mandatory for Android")
+  OPTION(ANDROID_HOST_COMPILER "Provide the host compiler used by Android (Mandatory)")
   IF(${ANDROID_HOST_COMPILER} STREQUAL "OFF")
     MESSAGE(FATAL_ERROR "-DANDROID_HOST_COMPILER=\"Compiler\" must be set")
   ENDIF()
@@ -316,7 +328,7 @@ ENDIF()
 SET(BUILT_IN_SHADER_GEN_CPP "${GENERATED_SHADER_DIR}/generated/builtin-shader-gen.cpp")
 ADD_CUSTOM_COMMAND(OUTPUT ${BUILT_IN_SHADER_GEN_CPP}
                    DEPENDS ${SHADER_GENERATOR_NAME}
-                   COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${SHADER_GENERATOR_NAME} ${SHADER_SOURCE_DIR} ${SHADER_GENERATED_DIR})
+                   COMMAND ${SHADER_GENERATOR_BINARY} ${SHADER_SOURCE_DIR} ${SHADER_GENERATED_DIR})
 
 SET(SOURCES ${SOURCES} ${BUILT_IN_SHADER_GEN_CPP})
 
index 7789dda..8891e9d 100644 (file)
@@ -14,6 +14,8 @@ if(CMAKE_BUILD_TYPE MATCHES Debug)
        add_definitions("-DDEBUG_ENABLED")
 endif()
 
+ADD_DEFINITIONS( "-DBUILDING_DALI_SCENE_LOADER" )
+
 foreach(flag ${PKGS_CFLAGS})
        set(extra_flags "${extra_flags} ${flag}")
 endforeach(flag)
@@ -86,10 +88,21 @@ SET_PROPERTY(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
              "${GENERATED_SHADER_DIR}/generated/"
              "${GENERATED_SHADER_DIR}/builtin-shader-extern-gen.h")
 
+IF( WIN32)
+  # When Using VCPKG, the default is always set to Debug if CMAKE_BUILD_TYPE is not set
+  IF( NOT CMAKE_BUILD_TYPE )
+    SET(SHADER_GENERATOR_BINARY ${CMAKE_CURRENT_BINARY_DIR}/../Debug/${SHADER_GENERATOR_NAME})
+  ELSE()
+    SET(SHADER_GENERATOR_BINARY ${CMAKE_CURRENT_BINARY_DIR}/../${CMAKE_BUILD_TYPE}/${SHADER_GENERATOR_NAME})
+  ENDIF()
+ELSE()
+  SET(SHADER_GENERATOR_BINARY ${CMAKE_CURRENT_BINARY_DIR}/../${SHADER_GENERATOR_NAME})
+ENDIF()
+
 SET( BUILT_IN_SHADER_GEN_CPP "${GENERATED_SHADER_DIR}/generated/builtin-shader-gen.cpp")
 ADD_CUSTOM_COMMAND(OUTPUT ${BUILT_IN_SHADER_GEN_CPP}
-                   DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../${SHADER_GENERATOR_NAME}
-                   COMMAND ${CMAKE_CURRENT_BINARY_DIR}/../${SHADER_GENERATOR_NAME} ${SHADER_SOURCE_DIR} ${SHADER_GENERATED_DIR})
+                   DEPENDS ${SHADER_GENERATOR_BINARY}
+                   COMMAND ${SHADER_GENERATOR_BINARY} ${SHADER_SOURCE_DIR} ${SHADER_GENERATED_DIR})
 
 SET( scene_loader_src_files ${scene_loader_src_files} ${BUILT_IN_SHADER_GEN_CPP} )
 
index 147b3fd..857163d 100644 (file)
@@ -161,7 +161,7 @@ bool ConvertPixelFormat(const uint32_t ktxPixelFormat, Pixel::Format& format)
     }
     case 0x8C3A: // GL_R11F_G11F_B10F
     {
-      format = Pixel::RGB32F;
+      format = Pixel::R11G11B10F;
       break;
     }
     case 0x8D7C: // GL_RGBA8UI
index 8317803..de37e30 100644 (file)
@@ -466,9 +466,9 @@ void MeshDefinition::Blob::ApplyMinMax(const std::vector<float>& min, const std:
                                 : (max.empty() ? [](const float* min, const float* max, uint32_t i, float& value) {
                                     value = std::max(min[i], value);
                                   }
-                                               : [](const float* min, const float* max, uint32_t i, float& value) {
+                                               : static_cast<ClampFn>([](const float* min, const float* max, uint32_t i, float& value) {
                                                    value = std::min(std::max(min[i], value), max[i]);
-                                                 });
+                                                 }));
 
   if(!clampFn)
   {
index dd1fc93..8756121 100644 (file)
@@ -168,7 +168,6 @@ Dali::Accessibility::States AccessibleImpl::CalculateStates()
   s[Dali::Accessibility::State::HIGHLIGHTED] = GetCurrentlyHighlightedActor() == self;
   s[Dali::Accessibility::State::ENABLED]     = true;
   s[Dali::Accessibility::State::SENSITIVE]   = true;
-  s[Dali::Accessibility::State::ANIMATED]    = self.GetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED).Get<bool>();
   s[Dali::Accessibility::State::VISIBLE]     = true;
   if(modal)
   {
@@ -262,7 +261,6 @@ static Dali::Actor CreateHighlightIndicatorActor()
   auto actor = Toolkit::ImageView::New(focusBorderImagePath);
   actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
   DevelControl::AppendAccessibilityAttribute(actor, "highlight", "");
-  actor.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED, true);
   actor.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, false);
 
   return actor;
index 3d340ec..4978e4d 100644 (file)
@@ -182,14 +182,7 @@ enum
    * @brief Set of accessibility attributes describing object in accessibility hierarchy
    * @details Name "accessibilityAttributes", type Property::MAP
    */
-  ACCESSIBILITY_ATTRIBUTES,
-
-  /**
-   * @brief Boolean flag describing object as animated
-   * @details Name "accessibilityAnimated", type Property::BOOLEAN
-   * @note Flag set to true will prevent BoundChanged accessibility signal from emiting
-   */
-  ACCESSIBILITY_ANIMATED
+  ACCESSIBILITY_ATTRIBUTES
 };
 
 } // namespace Property
index c73c582..665af7a 100644 (file)
@@ -187,6 +187,39 @@ enum Type
    * @details Name "grabHandleColor", type Property::VECTOR4.
    */
   GRAB_HANDLE_COLOR,
+
+  /**
+   * @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,
+
+  /**
+   * @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;
+   *
+   *   editor.SetProperty(DevelTextEditor::Property::INPUT_METHOD_SETTINGS, propertyMap);
+   * @endcode
+   */
+  INPUT_METHOD_SETTINGS,
 };
 
 } // namespace Property
index d3c201a..5cac9f4 100755 (executable)
@@ -89,7 +89,7 @@ Dali::Toolkit::WebBackForwardList* WebView::GetBackForwardList() const
   return Dali::Toolkit::GetImpl(*this).GetBackForwardList();
 }
 
-Dali::Toolkit::ImageView& WebView::GetFavicon()
+Dali::Toolkit::ImageView WebView::GetFavicon() const
 {
   return Dali::Toolkit::GetImpl(*this).GetFavicon();
 }
@@ -359,9 +359,9 @@ WebView::WebViewConsoleMessageSignalType& WebView::ConsoleMessageSignal()
   return Dali::Toolkit::GetImpl(*this).ConsoleMessageSignal();
 }
 
-WebView::WebViewPolicyDecisionSignalType& WebView::PolicyDecisionSignal()
+WebView::WebViewResponsePolicyDecisionSignalType& WebView::ResponsePolicyDecisionSignal()
 {
-  return Dali::Toolkit::GetImpl(*this).PolicyDecisionSignal();
+  return Dali::Toolkit::GetImpl(*this).ResponsePolicyDecisionSignal();
 }
 
 WebView::WebViewCertificateSignalType& WebView::CertificateConfirmSignal()
index 4f9159d..b290bfd 100755 (executable)
@@ -234,9 +234,9 @@ public:
   using WebViewConsoleMessageSignalType = Signal<void(WebView, std::shared_ptr<Dali::WebEngineConsoleMessage>)>;
 
   /**
-   * @brief WebView signal type related with policy decision.
+   * @brief WebView signal type related with response policy decision.
    */
-  using WebViewPolicyDecisionSignalType = Signal<void(WebView, std::shared_ptr<Dali::WebEnginePolicyDecision>)>;
+  using WebViewResponsePolicyDecisionSignalType = Signal<void(WebView, std::shared_ptr<Dali::WebEnginePolicyDecision>)>;
 
   /**
    * @brief WebView signal type related with certificate changed.
@@ -342,11 +342,11 @@ public:
   Dali::Toolkit::WebBackForwardList* GetBackForwardList() const;
 
   /**
-   * @brief Get Favicon of web page.
+   * @brief Get favicon of web page.
    *
-   * @return Handle to a fav icon
+   * @return Handle to a favicon
    */
-  Dali::Toolkit::ImageView& GetFavicon();
+  Dali::Toolkit::ImageView GetFavicon() const;
 
   /**
    * @brief Load a web page based on a given URL.
@@ -753,11 +753,11 @@ public:
   WebViewConsoleMessageSignalType& ConsoleMessageSignal();
 
   /**
-   * @brief Connect to this signal to be notified when new policy would be decided.
+   * @brief Connect to this signal to be notified when response policy would be decided.
    *
    * @return A signal object to connect with.
    */
-  WebViewPolicyDecisionSignalType& PolicyDecisionSignal();
+  WebViewResponsePolicyDecisionSignalType& ResponsePolicyDecisionSignal();
 
   /**
    * @brief Connect to this signal to be notified when certificate need be confirmed.
index f583d3c..e94f60b 100755 (executable)
@@ -46,6 +46,7 @@ SET( devel_api_src_files
   ${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}/focus-manager/focus-finder.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
@@ -188,6 +189,7 @@ SET( devel_api_shadow_view_header_files
 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
+  ${devel_api_src_dir}/focus-manager/focus-finder.h
 )
 
 SET( devel_api_image_loader_header_files
diff --git a/dali-toolkit/devel-api/focus-manager/focus-finder.cpp b/dali-toolkit/devel-api/focus-manager/focus-finder.cpp
new file mode 100644 (file)
index 0000000..d12ed11
--- /dev/null
@@ -0,0 +1,77 @@
+/*\r
+ * Copyright (c) 2021 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
+// CLASS HEADER\r
+#include "focus-finder.h"\r
+\r
+// EXTERNAL INCLUDES\r
+#include <dali/devel-api/common/singleton-service.h>\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali-toolkit/internal/focus-manager/focus-finder-impl.h>\r
+\r
+namespace Dali\r
+{\r
+namespace Toolkit\r
+{\r
+FocusFinder::FocusFinder()\r
+{\r
+}\r
+\r
+FocusFinder::~FocusFinder()\r
+{\r
+}\r
+\r
+FocusFinder FocusFinder::Get()\r
+{\r
+  FocusFinder finder;\r
+\r
+  // Check whether the focus finder is already created\r
+  SingletonService singletonService(SingletonService::Get());\r
+  if(singletonService)\r
+  {\r
+    Dali::BaseHandle handle = singletonService.GetSingleton(typeid(FocusFinder));\r
+    if(handle)\r
+    {\r
+      // If so, downcast the handle of singleton to focus finder\r
+      finder = FocusFinder(dynamic_cast<Internal::FocusFinder*>(handle.GetObjectPtr()));\r
+    }\r
+\r
+    if(!finder)\r
+    {\r
+      // If not, create the focus finder and register it as a singleton\r
+      finder = FocusFinder(new Internal::FocusFinder());\r
+      singletonService.Register(typeid(finder), finder);\r
+    }\r
+  }\r
+\r
+  return finder;\r
+}\r
+\r
+FocusFinder::FocusFinder(Internal::FocusFinder* impl)\r
+: BaseHandle(impl)\r
+{\r
+}\r
+\r
+Actor FocusFinder::GetNearestFocusableActor(Actor focusedActor, Toolkit::Control::KeyboardFocus::Direction direction)\r
+{\r
+  return GetImpl(*this).GetNearestFocusableActor(focusedActor, direction);\r
+}\r
+\r
+} // namespace Toolkit\r
+\r
+} // namespace Dali\r
diff --git a/dali-toolkit/devel-api/focus-manager/focus-finder.h b/dali-toolkit/devel-api/focus-manager/focus-finder.h
new file mode 100644 (file)
index 0000000..8012675
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef DALI_TOOLKIT_FOCUS_FINDER_H\r
+#define DALI_TOOLKIT_FOCUS_FINDER_H\r
+\r
+/*\r
+ * Copyright (c) 2021 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/control.h>\r
+\r
+namespace Dali\r
+{\r
+namespace Toolkit\r
+{\r
+namespace Internal DALI_INTERNAL\r
+{\r
+class FocusFinder;\r
+}\r
+\r
+/**\r
+ * FocusFinder\r
+ * This class used for finding the next focusable actor in a given direction\r
+ * from a actor that currently has focus.\r
+ */\r
+class DALI_TOOLKIT_API FocusFinder : public BaseHandle\r
+{\r
+public:\r
+  /**\r
+   * Create a FocusFinder handle; this can be initialised with FocusFinder::Get()\r
+   * Calling member functions with an uninitialised handle is not allowed.\r
+   */\r
+  FocusFinder();\r
+\r
+  /**\r
+   * @brief Destructor\r
+   *\r
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.\r
+   */\r
+  ~FocusFinder();\r
+\r
+  /**\r
+   * @brief Get the singleton of FocusFinder object.\r
+   * @return A handle to the FocusFinder control.\r
+   */\r
+  static FocusFinder Get();\r
+\r
+  /**\r
+   * Get the nearest focusable actor.\r
+   * @param [in] focusedActor The current focused actor.\r
+   * @param [in] direction The direction.\r
+   * @return The nearest focusable actor, or null if none exists.\r
+   */\r
+  Actor GetNearestFocusableActor(Actor focusedActor, Toolkit::Control::KeyboardFocus::Direction direction);\r
+\r
+private:\r
+  explicit DALI_INTERNAL FocusFinder(Internal::FocusFinder* impl);\r
+\r
+}; // class FocusFinder\r
+\r
+} // namespace Toolkit\r
+\r
+} // namespace Dali\r
+\r
+#endif // DALI_TOOLKIT_FOCUS_FINDER_H\r
index d19c90b..a7349fe 100644 (file)
@@ -55,7 +55,8 @@ enum class Justification
   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
+  SPACE_AROUND,  ///< Items are positioned with equal space before, and after the items
+  SPACE_EVENLY   ///< Items are positioned with equal space before, between, and after the items
 };
 
 /**
index 0163cc6..a74af43 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_TEXT_ENUMERATIONS_DEVEL_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -44,6 +44,17 @@ enum Type
 };
 
 } // namespace VerticalLineAlignment
+namespace LineWrap
+{
+enum Mode
+{
+  WORD,
+  CHARACTER,
+  HYPHENATION, // HYPHENATION mode will add hyphen and move part of the word to the next line.
+  MIXED        // MIXEd mode will apply WORD mode, if failed try HYPHENATION mode, if failed try CHARACTER.
+};
+
+} // namespace LineWrap
 
 } // namespace DevelText
 
index 1441dc4..a4dbce4 100644 (file)
@@ -173,7 +173,8 @@ void ShapeTextPreprocess(const RendererParameters& textParameters, TextAbstracti
   MarkupProcessData markupProcessData(colorRuns,
                                       fontDescriptionRuns,
                                       textModel->mLogicalModel->mEmbeddedItems,
-                                      textModel->mLogicalModel->mAnchors);
+                                      textModel->mLogicalModel->mAnchors,
+                                      textModel->mLogicalModel->mUnderlinedCharacterRuns);
 
   if(textParameters.markupEnabled)
   {
@@ -1029,7 +1030,7 @@ Size LayoutText(const RendererParameters& textParameters, TextAbstraction::TextR
   // Resize the vector of positions to have the same size than the vector of glyphs.
   rendererParameters.positions.Resize(numberOfGlyphs);
 
-  textModel->mLineWrapMode                 = LineWrap::WORD;
+  textModel->mLineWrapMode                 = Text::LineWrap::WORD;
   textModel->mIgnoreSpacesAfterText        = false;
   textModel->mMatchSystemLanguageDirection = false;
   Text::Layout::Parameters layoutParameters(internalDataModel.textLayoutArea,
index 7f462f6..78a6268 100644 (file)
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2020 Samsung Electronics Co., Ltd.
+* Copyright (c) 2021 Samsung Electronics Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -175,6 +175,7 @@ void GetRedOffsetAndMask(Dali::Pixel::Format pixelFormat, int32_t& byteOffset, i
     case Dali::Pixel::DEPTH_UNSIGNED_INT:
     case Dali::Pixel::DEPTH_FLOAT:
     case Dali::Pixel::DEPTH_STENCIL:
+    case Dali::Pixel::R11G11B10F:
     {
       DALI_LOG_ERROR("Pixel format not compatible.\n");
       byteOffset = 0;
index 448bf88..bae7111 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_COLOR_VISUAL_PROPERTIES_DEVEL_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -40,14 +40,6 @@ 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, animatable.
    *          If the value is 0, the edge is sharp. Otherwise, the larger the value, the more the edge is blurred.
index 1098b7d..ddb02d5 100644 (file)
@@ -94,6 +94,28 @@ enum Type
    *       If it it RELATIVE, the corner radius value is relative to the smaller of the visual width and visual height.
    */
   CORNER_RADIUS_POLICY = OPACITY + 3,
+
+  /**
+   * @brief The width for the borderline of the visual
+   * @details Name "borderlineWidth", type Property::FLOAT, animatable
+   * @note Optional. Default value is 0.0f.
+   */
+  BORDERLINE_WIDTH = OPACITY + 4,
+
+  /**
+   * @brief The color for the borderline of the visual
+   * @details Name "borderlineColor", type Property::VECTOR4, animatable
+   * @note Default value is Color::BLACK
+   */
+  BORDERLINE_COLOR = OPACITY + 5,
+
+  /**
+   * @brief The offset from the visual borderline (recommend [-1.0f to 1.0f]).
+   * @details Name "borderlineOffset", type Property::FLOAT, animatable
+   * @note Default value is 0.0f.
+   * @note This value will be clipped by [-1.0f to 1.0f].
+   */
+  BORDERLINE_OFFSET = OPACITY + 6,
 };
 
 } // namespace Property
index 070fa82..c50cd20 100644 (file)
@@ -420,7 +420,6 @@ const PropertyRegistration Control::Impl::PROPERTY_18(typeRegistration, "accessi
 const PropertyRegistration Control::Impl::PROPERTY_19(typeRegistration, "accessibilityTranslationDomain", Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN, Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty);
 const PropertyRegistration Control::Impl::PROPERTY_20(typeRegistration, "accessibilityRole",              Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE,               Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
 const PropertyRegistration Control::Impl::PROPERTY_21(typeRegistration, "accessibilityHighlightable",     Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE,      Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
-const PropertyRegistration Control::Impl::PROPERTY_22(typeRegistration, "accessibilityAnimated",          Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED,           Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
 // clang-format on
 
 Control::Impl::Impl(Control& controlImpl)
@@ -487,7 +486,6 @@ Control::Impl::~Impl()
     StopObservingVisual(iter->visual);
   }
 
-  AccessibilityDeregister(false);
   // All gesture detectors will be destroyed so no need to disconnect.
   delete mStartingPinchScale;
 
@@ -1235,16 +1233,6 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
         }
         break;
       }
-
-      case Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED:
-      {
-        bool animated;
-        if(value.Get(animated))
-        {
-          controlImpl.mImpl->mAccessibilityAnimated = animated;
-        }
-        break;
-      }
     }
   }
 }
@@ -1405,12 +1393,6 @@ Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index i
         value = controlImpl.mImpl->mAccessibilityAttributes;
         break;
       }
-
-      case Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED:
-      {
-        value = controlImpl.mImpl->mAccessibilityAnimated;
-        break;
-      }
     }
   }
 
@@ -1471,6 +1453,15 @@ Dali::Accessibility::ReadingInfoTypes Control::Impl::GetAccessibilityReadingInfo
   {
     place->Get(value);
   }
+  else
+  {
+    Dali::Accessibility::ReadingInfoTypes types;
+    types[Dali::Accessibility::ReadingInfoType::NAME] = true;
+    types[Dali::Accessibility::ReadingInfoType::ROLE] = true;
+    types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
+    types[Dali::Accessibility::ReadingInfoType::STATE] = true;
+    return types;
+  }
 
   if(value.empty())
   {
@@ -1903,76 +1894,6 @@ Dali::Accessibility::Accessible* Control::Impl::GetAccessibilityObject(Dali::Act
   return nullptr;
 }
 
-void Control::Impl::PositionOrSizeChangedCallback(PropertyNotification& p)
-{
-  auto self = Dali::Actor::DownCast(p.GetTarget());
-  if(Dali::Accessibility::IsUp() && !self.GetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED).Get<bool>())
-  {
-    auto extents = DevelActor::CalculateScreenExtents(self);
-    Dali::Accessibility::Accessible::Get(self)->EmitBoundsChanged(extents);
-  }
-}
-
-void Control::Impl::CulledChangedCallback(PropertyNotification& p)
-{
-  if(Dali::Accessibility::IsUp())
-  {
-    auto self = Dali::Actor::DownCast(p.GetTarget());
-    Dali::Accessibility::Accessible::Get(self)->EmitShowing(!self.GetProperty(DevelActor::Property::CULLED).Get<bool>());
-  }
-}
-
-void Control::Impl::AccessibilityRegister()
-{
-  if(!accessibilityNotificationSet)
-  {
-    accessibilityNotificationPosition = mControlImpl.Self().AddPropertyNotification(Actor::Property::POSITION, StepCondition(0.01f));
-    accessibilityNotificationPosition.SetNotifyMode(PropertyNotification::NOTIFY_ON_CHANGED);
-    accessibilityNotificationPosition.NotifySignal().Connect(&Control::Impl::PositionOrSizeChangedCallback);
-
-    accessibilityNotificationSize = mControlImpl.Self().AddPropertyNotification(Actor::Property::SIZE, StepCondition(0.01f));
-    accessibilityNotificationSize.SetNotifyMode(PropertyNotification::NOTIFY_ON_CHANGED);
-    accessibilityNotificationSize.NotifySignal().Connect(&Control::Impl::PositionOrSizeChangedCallback);
-
-    accessibilityNotificationCulled = mControlImpl.Self().AddPropertyNotification(DevelActor::Property::CULLED, LessThanCondition(0.5f));
-    accessibilityNotificationCulled.SetNotifyMode(PropertyNotification::NOTIFY_ON_CHANGED);
-    accessibilityNotificationCulled.NotifySignal().Connect(&Control::Impl::CulledChangedCallback);
-
-    accessibilityNotificationSet = true;
-  }
-}
-
-void Control::Impl::AccessibilityDeregister(bool remove)
-{
-  if(accessibilityNotificationSet)
-  {
-    accessibilityNotificationPosition.NotifySignal().Disconnect(&Control::Impl::PositionOrSizeChangedCallback);
-    if(remove)
-    {
-      mControlImpl.Self().RemovePropertyNotification(accessibilityNotificationPosition);
-    }
-    accessibilityNotificationPosition.Reset();
-    accessibilityNotificationPosition = {};
-
-    accessibilityNotificationSize.NotifySignal().Disconnect(&Control::Impl::PositionOrSizeChangedCallback);
-    if(remove)
-    {
-      mControlImpl.Self().RemovePropertyNotification(accessibilityNotificationSize);
-    }
-    accessibilityNotificationSize.Reset();
-    accessibilityNotificationSize     = {};
-
-    accessibilityNotificationCulled.NotifySignal().Disconnect(&Control::Impl::CulledChangedCallback);
-    if(remove)
-    {
-      mControlImpl.Self().RemovePropertyNotification(accessibilityNotificationCulled);
-    }
-    accessibilityNotificationCulled.Reset();
-    accessibilityNotificationCulled   = {};
-    accessibilityNotificationSet      = false;
-  }
-}
-
 } // namespace Internal
 
 } // namespace Toolkit
index a3ab6c0..45430c5 100644 (file)
@@ -489,7 +489,6 @@ public:
   Dali::Accessibility::Role mAccessibilityRole = Dali::Accessibility::Role::UNKNOWN;
 
   std::vector<std::vector<Accessibility::Address>> mAccessibilityRelations;
-  bool                                             mAccessibilityAnimated = false;
 
   // Gesture Detection
   PinchGestureDetector     mPinchGestureDetector;
@@ -543,15 +542,8 @@ public:
   static Dali::Accessibility::Accessible* GetAccessibilityObject(Dali::Actor actor);
   Dali::Accessibility::Accessible*        GetAccessibilityObject();
 
-  void AccessibilityRegister();
-  void AccessibilityDeregister(bool remove);
-
   std::function<std::unique_ptr<Dali::Accessibility::Accessible>(Actor)> accessibilityConstructor;
   std::unique_ptr<Dali::Accessibility::Accessible>                       accessibilityObject;
-  Dali::PropertyNotification                                             accessibilityNotificationPosition, accessibilityNotificationSize, accessibilityNotificationCulled;
-  bool                                                                   accessibilityNotificationSet = false;
-  static void                                                            PositionOrSizeChangedCallback(PropertyNotification&);
-  static void                                                            CulledChangedCallback(PropertyNotification&);
 };
 
 } // namespace Internal
index 111e480..a3c092d 100644 (file)
@@ -127,7 +127,8 @@ const Scripting::StringEnum JUSTIFY_CONTENT_STRING_TABLE[] =
     {"center", Toolkit::FlexContainer::JUSTIFY_CENTER},
     {"flexEnd", Toolkit::FlexContainer::JUSTIFY_FLEX_END},
     {"spaceBetween", Toolkit::FlexContainer::JUSTIFY_SPACE_BETWEEN},
-    {"spaceAround", Toolkit::FlexContainer::JUSTIFY_SPACE_AROUND}};
+    {"spaceAround", Toolkit::FlexContainer::JUSTIFY_SPACE_AROUND},
+    {"spaceEvenly", Toolkit::FlexContainer::JUSTIFY_SPACE_EVENLY}};
 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[] =
index 7347c00..9b9e7d9 100644 (file)
@@ -147,6 +147,8 @@ DALI_DEVEL_PROPERTY_REGISTRATION_READ_ONLY(Toolkit, TextEditor, "selectedText",
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "fontSizeScale",                        FLOAT,     FONT_SIZE_SCALE                     )
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "primaryCursorPosition",                INTEGER,   PRIMARY_CURSOR_POSITION             )
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "grabHandleColor",                      VECTOR4,   GRAB_HANDLE_COLOR                   )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "enableGrabHandlePopup",                BOOLEAN,   ENABLE_GRAB_HANDLE_POPUP            )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "inputMethodSettings",                  MAP,       INPUT_METHOD_SETTINGS               )
 
 DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "textChanged",        SIGNAL_TEXT_CHANGED       )
 DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "inputStyleChanged",  SIGNAL_INPUT_STYLE_CHANGED)
@@ -775,6 +777,30 @@ void TextEditor::SetProperty(BaseObject* object, Property::Index index, const Pr
         impl.RequestTextRelayout();
         break;
       }
+      case Toolkit::DevelTextEditor::Property::ENABLE_GRAB_HANDLE_POPUP:
+      {
+        const bool grabHandlePopupEnabled = value.Get<bool>();
+        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p ENABLE_GRAB_HANDLE_POPUP %d\n", impl.mController.Get(), grabHandlePopupEnabled);
+
+        impl.mController->SetGrabHandlePopupEnabled(grabHandlePopupEnabled);
+        break;
+      }
+      case Toolkit::DevelTextEditor::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 == textEditor)
+        {
+          impl.mInputMethodContext.ApplyOptions(impl.mInputMethodOptions);
+        }
+        break;
+      }
     } // switch
   }   // texteditor
 }
@@ -1136,6 +1162,18 @@ Property::Value TextEditor::GetProperty(BaseObject* object, Property::Index inde
         value = impl.mDecorator->GetHandleColor();
         break;
       }
+      case Toolkit::DevelTextEditor::Property::ENABLE_GRAB_HANDLE_POPUP:
+      {
+        value = impl.mController->IsGrabHandlePopupEnabled();
+        break;
+      }
+      case Toolkit::DevelTextEditor::Property::INPUT_METHOD_SETTINGS:
+      {
+        Property::Map map;
+        impl.mInputMethodOptions.RetrieveProperty(map);
+        value = map;
+        break;
+      }
     } //switch
   }
 
@@ -1456,6 +1494,12 @@ void TextEditor::OnRelayout(const Vector2& size, RelayoutContainer& container)
     ResizeActor(mActiveLayer, contentSize);
   }
 
+  // If there is text changed, callback is called.
+  if(mTextChanged)
+  {
+    EmitTextChangedSignal();
+  }
+
   const Text::Controller::UpdateTextType updateTextType = mController->Relayout(contentSize, layoutDirection);
 
   if((Text::Controller::NONE_UPDATED != updateTextType) ||
@@ -1475,12 +1519,6 @@ void TextEditor::OnRelayout(const Vector2& size, RelayoutContainer& container)
     }
 
     RenderText(updateTextType);
-
-    // If there is text changed, callback is called.
-    if(mTextChanged)
-    {
-      EmitTextChangedSignal();
-    }
   }
 
   // The text-editor emits signals when the input style changes. These changes of style are
@@ -1555,6 +1593,7 @@ void TextEditor::OnKeyInputFocusGained()
   if(mInputMethodContext && IsEditable())
   {
     // All input panel properties, such as layout, return key type, and input hint, should be set before input panel activates (or shows).
+    mInputMethodContext.ApplyOptions(mInputMethodOptions);
     mInputMethodContext.NotifyTextInputMultiLine(true);
 
     mInputMethodContext.StatusChangedSignal().Connect(this, &TextEditor::KeyboardStatusChanged);
@@ -2247,7 +2286,22 @@ bool TextEditor::AccessibleImpl::CutText(size_t startPosition,
   Dali::Toolkit::GetImpl(slf).getController()->CopyStringToClipboard(txt.substr(startPosition, endPosition - startPosition));
 
   slf.SetProperty(Toolkit::TextEditor::Property::TEXT,
-                  txt.substr(0, startPosition) + txt.substr(endPosition - startPosition, txt.size()));
+                  txt.substr(0, startPosition) + txt.substr(endPosition));
+
+  return true;
+}
+
+bool TextEditor::AccessibleImpl::DeleteText(size_t startPosition,
+                                            size_t endPosition)
+{
+  if(endPosition <= startPosition)
+    return false;
+
+  auto slf = Toolkit::TextEditor::DownCast(Self());
+  auto txt = slf.GetProperty(Toolkit::TextEditor::Property::TEXT).Get<std::string>();
+
+  slf.SetProperty(Toolkit::TextEditor::Property::TEXT,
+                  txt.substr(0, startPosition) + txt.substr(endPosition));
 
   return true;
 }
@@ -2269,6 +2323,26 @@ Dali::Accessibility::States TextEditor::AccessibleImpl::CalculateStates()
   return states;
 }
 
+bool TextEditor::AccessibleImpl::InsertText(size_t startPosition,
+                                            std::string text)
+{
+  auto slf = Toolkit::TextEditor::DownCast(Self());
+  auto txt = slf.GetProperty(Toolkit::TextEditor::Property::TEXT).Get<std::string>();
+
+  txt.insert(startPosition, text);
+
+  slf.SetProperty(Toolkit::TextEditor::Property::TEXT, std::move(txt));
+
+  return true;
+}
+
+bool TextEditor::AccessibleImpl::SetTextContents(std::string newContents)
+{
+  auto slf = Toolkit::TextEditor::DownCast(Self());
+  slf.SetProperty(Toolkit::TextEditor::Property::TEXT, std::move(newContents));
+  return true;
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index d0609b6..9a06ea5 100644 (file)
@@ -409,6 +409,7 @@ private: // Data
   Dali::Animation               mAnimation; ///< Scroll indicator Show/Hide Animation.
   Dali::TimePeriod              mAnimationPeriod;
   std::vector<Actor>            mClippingDecorationActors; ///< Decoration actors which need clipping.
+  Dali::InputMethodOptions      mInputMethodOptions;
 
   Actor         mRenderableActor;
   Actor         mActiveLayer;
@@ -442,6 +443,9 @@ private: // Data
     bool                  CopyText(size_t startPosition, size_t endPosition) override;
     bool                  CutText(size_t startPosition, size_t endPosition) override;
     Accessibility::States CalculateStates() override;
+    bool                  InsertText(size_t startPosition, std::string text) override;
+    bool                  SetTextContents(std::string newContents) override;
+    bool                  DeleteText(size_t startPosition, size_t endPosition) override;
   };
 };
 
index 7fc3eca..4e5cd9c 100644 (file)
@@ -1407,6 +1407,12 @@ void TextField::OnRelayout(const Vector2& size, RelayoutContainer& container)
     ResizeActor(mActiveLayer, contentSize);
   }
 
+  // If there is text changed, callback is called.
+  if(mTextChanged)
+  {
+    EmitTextChangedSignal();
+  }
+
   const Text::Controller::UpdateTextType updateTextType = mController->Relayout(contentSize, layoutDirection);
 
   if((Text::Controller::NONE_UPDATED != updateTextType) ||
@@ -1426,12 +1432,6 @@ void TextField::OnRelayout(const Vector2& size, RelayoutContainer& container)
     }
 
     RenderText(updateTextType);
-
-    // If there is text changed, callback is called.
-    if(mTextChanged)
-    {
-      EmitTextChangedSignal();
-    }
   }
 
   // The text-field emits signals when the input style changes. These changes of style are
@@ -2128,7 +2128,22 @@ bool TextField::AccessibleImpl::CutText(size_t startPosition,
   Dali::Toolkit::GetImpl(slf).getController()->CopyStringToClipboard(txt.substr(startPosition, endPosition - startPosition));
 
   slf.SetProperty(Toolkit::TextField::Property::TEXT,
-                  txt.substr(0, startPosition) + txt.substr(endPosition - startPosition, txt.size()));
+                  txt.substr(0, startPosition) + txt.substr(endPosition));
+
+  return true;
+}
+
+bool TextField::AccessibleImpl::DeleteText(size_t startPosition,
+                                           size_t endPosition)
+{
+  if(endPosition <= startPosition)
+    return false;
+
+  auto slf = Toolkit::TextField::DownCast(Self());
+  auto txt = slf.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
+
+  slf.SetProperty(Toolkit::TextField::Property::TEXT,
+                  txt.substr(0, startPosition) + txt.substr(endPosition));
 
   return true;
 }
@@ -2151,6 +2166,26 @@ Dali::Accessibility::States TextField::AccessibleImpl::CalculateStates()
   return states;
 }
 
+bool TextField::AccessibleImpl::InsertText(size_t startPosition,
+                                            std::string text)
+{
+  auto slf = Toolkit::TextField::DownCast(Self());
+  auto txt = slf.GetProperty(Toolkit::TextField::Property::TEXT).Get<std::string>();
+
+  txt.insert(startPosition, text);
+
+  slf.SetProperty(Toolkit::TextField::Property::TEXT, std::move(txt));
+
+  return true;
+}
+
+bool TextField::AccessibleImpl::SetTextContents(std::string newContents)
+{
+  auto slf = Toolkit::TextField::DownCast(Self());
+  slf.SetProperty(Toolkit::TextField::Property::TEXT, std::move(newContents));
+  return true;
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index 670b81c..c76f05a 100644 (file)
@@ -398,6 +398,9 @@ protected:
     bool                  CopyText(size_t startPosition, size_t endPosition) override;
     bool                  CutText(size_t startPosition, size_t endPosition) override;
     Accessibility::States CalculateStates() override;
+    bool                  InsertText(size_t startPosition, std::string text) override;
+    bool                  SetTextContents(std::string newContents) override;
+    bool                  DeleteText(size_t startPosition, size_t endPosition) override;
   };
 };
 
index 1beb1c2..52f9c29 100644 (file)
@@ -19,6 +19,7 @@
 #include <dali-toolkit/internal/controls/text-controls/text-label-impl.h>
 
 // EXTERNAL INCLUDES
+#include <dali/devel-api/actors/actor-devel.h>
 #include <dali/devel-api/adaptor-framework/image-loading.h>
 #include <dali/devel-api/adaptor-framework/window-devel.h>
 #include <dali/devel-api/common/stage.h>
@@ -839,6 +840,9 @@ void TextLabel::OnTap(const TapGesture& gesture)
   padding                   = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
   const Vector2& localPoint = gesture.GetLocalPoint();
   mController->AnchorEvent(localPoint.x - padding.start, localPoint.y - padding.top);
+
+  // parents can also listen for tap gesture events
+  Dali::DevelActor::SetNeedGesturePropagation(Self(), true);
 }
 
 void TextLabel::AnchorClicked(const std::string& href)
index 85b219e..181a47e 100644 (file)
@@ -21,6 +21,7 @@
 // EXTERNAL INCLUDES
 #include <dali/devel-api/actors/actor-devel.h>
 #include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/devel-api/rendering/texture-devel.h>
 #include <dali/devel-api/scripting/scripting.h>
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/adaptor-framework/native-image-source.h>
@@ -122,6 +123,9 @@ void VideoView::OnInitialize()
       new DevelControl::AccessibleImpl(actor, Dali::Accessibility::Role::VIDEO));
   });
 
+  //Enable highightability
+  Self().SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true);
+
   //update self property
   self.RegisterProperty(IS_VIDEO_VIEW_PROPERTY_NAME, true, Property::READ_WRITE);
 }
@@ -869,7 +873,7 @@ void VideoView::PlayAnimation(Dali::Animation animation)
 
 Dali::Shader VideoView::CreateShader()
 {
-  std::string fragmentShader = "#extension GL_OES_EGL_image_external:require\n";
+  std::string fragmentShader;
   std::string vertexShader;
   std::string customFragmentShader;
   bool        checkShader = false;
@@ -900,13 +904,15 @@ Dali::Shader VideoView::CreateShader()
 
     if(!fragmentShaderValue || !checkShader)
     {
-      fragmentShader += SHADER_VIDEO_VIEW_TEXTURE_FRAG.data();
+      fragmentShader = SHADER_VIDEO_VIEW_TEXTURE_FRAG.data();
+      DevelTexture::ApplyNativeFragmentShader(mNativeTexture, fragmentShader);
     }
   }
   else
   {
-    vertexShader = SHADER_VIDEO_VIEW_TEXTURE_VERT.data();
-    fragmentShader += SHADER_VIDEO_VIEW_TEXTURE_FRAG.data();
+    vertexShader   = SHADER_VIDEO_VIEW_TEXTURE_VERT.data();
+    fragmentShader = SHADER_VIDEO_VIEW_TEXTURE_FRAG.data();
+    DevelTexture::ApplyNativeFragmentShader(mNativeTexture, fragmentShader);
   }
 
   return Dali::Shader::New(vertexShader, fragmentShader);
old mode 100644 (file)
new mode 100755 (executable)
index 6a3af8d..3342374
@@ -97,7 +97,7 @@ DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "formRepostDecision",      FORM_REPOS
 DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "frameRendered",           FRAME_RENDERED_SIGNAL            )
 DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "requestInterceptor",      REQUEST_INTERCEPTOR_SIGNAL       )
 DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "consoleMessage",          CONSOLE_MESSAGE_SIGNAL           )
-DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "policyDecision",          POLICY_DECISION                  )
+DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "responsePolicyDecided",   POLICY_DECISION                  )
 DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "certificateConfirm",      CERTIFICATE_CONFIRM_SIGNAL       )
 DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "sslCertificateChanged",   SSL_CERTIFICATE_CHANGED_SIGNAL   )
 DALI_SIGNAL_REGISTRATION(Toolkit, WebView, "httpAuthRequest",         HTTP_AUTH_REQUEST_SIGNAL         )
@@ -234,7 +234,7 @@ void WebView::OnInitialize()
     mWebEngine.FrameRenderedSignal().Connect(this, &WebView::OnFrameRendered);
     mWebEngine.RequestInterceptorSignal().Connect(this, &WebView::OnInterceptRequest);
     mWebEngine.ConsoleMessageSignal().Connect(this, &WebView::OnConsoleMessage);
-    mWebEngine.PolicyDecisionSignal().Connect(this, &WebView::OnPolicyDecisionRequest);
+    mWebEngine.ResponsePolicyDecisionSignal().Connect(this, &WebView::OnResponsePolicyDecided);
     mWebEngine.CertificateConfirmSignal().Connect(this, &WebView::OnCertificateConfirm);
     mWebEngine.SslCertificateChangedSignal().Connect(this, &WebView::OnSslCertificateChanged);
     mWebEngine.HttpAuthHandlerSignal().Connect(this, &WebView::OnHttpAuthenticationRequest);
@@ -268,14 +268,15 @@ Dali::Toolkit::WebBackForwardList* WebView::GetBackForwardList() const
   return mWebBackForwardList.get();
 }
 
-Dali::Toolkit::ImageView& WebView::GetFavicon()
+Dali::Toolkit::ImageView WebView::GetFavicon() const
 {
+  Dali::Toolkit::ImageView faviconView;
   if(mWebEngine)
   {
     Dali::PixelData pixelData = mWebEngine.GetFavicon();
-    mFaviconView              = CreateImageView(pixelData);
+    faviconView               = CreateImageView(pixelData);
   }
-  return mFaviconView;
+  return faviconView;
 }
 
 void WebView::LoadUrl(const std::string& url)
@@ -706,8 +707,13 @@ void WebView::EnableBlendMode(bool blendEnabled)
   }
 }
 
-Dali::Toolkit::ImageView WebView::CreateImageView(Dali::PixelData pixel)
+Dali::Toolkit::ImageView WebView::CreateImageView(Dali::PixelData pixel) const
 {
+  if(!pixel)
+  {
+    return Dali::Toolkit::ImageView();
+  }
+
   std::string              url       = Dali::Toolkit::Image::GenerateUrl(pixel);
   Dali::Toolkit::ImageView imageView = Dali::Toolkit::ImageView::New(url);
   imageView.SetProperty(Dali::Actor::Property::SIZE, Vector2(pixel.GetWidth(), pixel.GetHeight()));
@@ -764,9 +770,9 @@ Dali::Toolkit::WebView::WebViewConsoleMessageSignalType& WebView::ConsoleMessage
   return mConsoleMessageSignal;
 }
 
-Dali::Toolkit::WebView::WebViewPolicyDecisionSignalType& WebView::PolicyDecisionSignal()
+Dali::Toolkit::WebView::WebViewResponsePolicyDecisionSignalType& WebView::ResponsePolicyDecisionSignal()
 {
-  return mPolicyDecisionSignal;
+  return mResponsePolicyDecisionSignal;
 }
 
 Dali::Toolkit::WebView::WebViewCertificateSignalType& WebView::CertificateConfirmSignal()
@@ -901,12 +907,12 @@ void WebView::OnConsoleMessage(std::shared_ptr<Dali::WebEngineConsoleMessage> me
   }
 }
 
-void WebView::OnPolicyDecisionRequest(std::shared_ptr<Dali::WebEnginePolicyDecision> decision)
+void WebView::OnResponsePolicyDecided(std::shared_ptr<Dali::WebEnginePolicyDecision> decision)
 {
-  if(!mPolicyDecisionSignal.Empty())
+  if(!mResponsePolicyDecisionSignal.Empty())
   {
     Dali::Toolkit::WebView handle(GetOwner());
-    mPolicyDecisionSignal.Emit(handle, std::move(decision));
+    mResponsePolicyDecisionSignal.Emit(handle, std::move(decision));
   }
 }
 
@@ -1014,7 +1020,7 @@ bool WebView::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tr
   }
   else if(0 == strcmp(signalName.c_str(), POLICY_DECISION))
   {
-    webView.PolicyDecisionSignal().Connect(tracker, functor);
+    webView.ResponsePolicyDecisionSignal().Connect(tracker, functor);
     connected = true;
   }
   else if(0 == strcmp(signalName.c_str(), CERTIFICATE_CONFIRM_SIGNAL))
index 4031ee6..a5cefa4 100755 (executable)
@@ -95,7 +95,7 @@ public:
   /**
    * @copydoc Dali::Toolkit::WebView::GetFavicon()
    */
-  Dali::Toolkit::ImageView& GetFavicon();
+  Dali::Toolkit::ImageView GetFavicon() const;
 
   /**
    * @copydoc Dali::Toolkit::WebView::LoadUrl()
@@ -358,9 +358,9 @@ public:
   Dali::Toolkit::WebView::WebViewConsoleMessageSignalType& ConsoleMessageSignal();
 
   /**
-   * @copydoc Dali::Toolkit::WebView::PolicyDecisionSignal()
+   * @copydoc Dali::Toolkit::WebView::ResponsePolicyDecisionSignal()
    */
-  Dali::Toolkit::WebView::WebViewPolicyDecisionSignalType& PolicyDecisionSignal();
+  Dali::Toolkit::WebView::WebViewResponsePolicyDecisionSignalType& ResponsePolicyDecisionSignal();
 
   /**
    * @copydoc Dali::Toolkit::WebView::CertificateConfirmSignal()
@@ -608,7 +608,7 @@ private:
    * @param[in] pixel Pixel data
    * @return The new image view
    */
-  Dali::Toolkit::ImageView CreateImageView(Dali::PixelData pixel);
+  Dali::Toolkit::ImageView CreateImageView(Dali::PixelData pixel) const;
 
   /**
    * @brief Callback function to be called when page load started.
@@ -709,10 +709,10 @@ private:
   void OnConsoleMessage(std::shared_ptr<Dali::WebEngineConsoleMessage> message);
 
   /**
-   * @brief Callback function to be called when policy need be decided.
+   * @brief Callback function to be called when response policy need be decided.
    * @param[in] decision The policy decided.
    */
-  void OnPolicyDecisionRequest(std::shared_ptr<Dali::WebEnginePolicyDecision> decision);
+  void OnResponsePolicyDecided(std::shared_ptr<Dali::WebEnginePolicyDecision> decision);
 
   /**
    * @brief Callback function to be called when certificate need be confirmed.
@@ -760,7 +760,7 @@ private:
   Dali::Toolkit::WebView::WebViewFrameRenderedSignalType           mFrameRenderedSignal;
   Dali::Toolkit::WebView::WebViewRequestInterceptorSignalType      mRequestInterceptorSignal;
   Dali::Toolkit::WebView::WebViewConsoleMessageSignalType          mConsoleMessageSignal;
-  Dali::Toolkit::WebView::WebViewPolicyDecisionSignalType          mPolicyDecisionSignal;
+  Dali::Toolkit::WebView::WebViewResponsePolicyDecisionSignalType  mResponsePolicyDecisionSignal;
   Dali::Toolkit::WebView::WebViewCertificateSignalType             mCertificateConfirmSignal;
   Dali::Toolkit::WebView::WebViewCertificateSignalType             mSslCertificateChangedSignal;
   Dali::Toolkit::WebView::WebViewHttpAuthHandlerSignalType         mHttpAuthHandlerSignal;
@@ -772,8 +772,6 @@ private:
   std::unique_ptr<Dali::Toolkit::WebSettings>        mWebSettings;
   std::unique_ptr<Dali::Toolkit::WebBackForwardList> mWebBackForwardList;
 
-  Dali::Toolkit::ImageView mFaviconView;
-
   Dali::PropertyNotification mPositionUpdateNotification;
   Dali::PropertyNotification mSizeUpdateNotification;
   Dali::PropertyNotification mScaleUpdateNotification;
index 35ac87b..fc8edaf 100644 (file)
@@ -114,6 +114,7 @@ SET( toolkit_src_files
 
    ${toolkit_src_dir}/focus-manager/keyboard-focus-manager-impl.cpp
    ${toolkit_src_dir}/focus-manager/keyinput-focus-manager-impl.cpp
+   ${toolkit_src_dir}/focus-manager/focus-finder-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
@@ -142,6 +143,7 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/text/property-string-parser.cpp
    ${toolkit_src_dir}/text/segmentation.cpp
    ${toolkit_src_dir}/text/shaper.cpp
+   ${toolkit_src_dir}/text/hyphenator.cpp
    ${toolkit_src_dir}/text/text-enumerations-impl.cpp
    ${toolkit_src_dir}/text/text-controller.cpp
    ${toolkit_src_dir}/text/text-controller-event-handler.cpp
diff --git a/dali-toolkit/internal/focus-manager/focus-finder-impl.cpp b/dali-toolkit/internal/focus-manager/focus-finder-impl.cpp
new file mode 100644 (file)
index 0000000..93f1d65
--- /dev/null
@@ -0,0 +1,449 @@
+/*\r
+ * Copyright (c) 2021 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
+/*\r
+ * Copyright (C) 2017 The Android Open Source Project\r
+ *\r
+ * Modified by joogab yun(joogab.yun@samsung.com)\r
+ */\r
+\r
+// CLASS HEADER\r
+#include "focus-finder-impl.h"\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali/devel-api/actors/actor-devel.h>\r
+\r
+// EXTERNAL INCLUDES\r
+#include <dali/integration-api/adaptor-framework/adaptor.h>\r
+#include <dali/integration-api/adaptor-framework/scene-holder.h>\r
+#include <dali/integration-api/debug.h>\r
+#include <dali/public-api/actors/layer.h>\r
+#include <math.h>\r
+\r
+namespace\r
+{\r
+static int MajorAxisDistanceRaw(Dali::Toolkit::Control::KeyboardFocus::Direction direction, Dali::Rect<float> source, Dali::Rect<float> dest)\r
+{\r
+  switch(direction)\r
+  {\r
+    case Dali::Toolkit::Control::KeyboardFocus::LEFT:\r
+    {\r
+      return source.left - dest.right;\r
+    }\r
+    case Dali::Toolkit::Control::KeyboardFocus::RIGHT:\r
+    {\r
+      return dest.left - source.right;\r
+    }\r
+    case Dali::Toolkit::Control::KeyboardFocus::UP:\r
+    {\r
+      return source.top - dest.bottom;\r
+    }\r
+    case Dali::Toolkit::Control::KeyboardFocus::DOWN:\r
+    {\r
+      return dest.top - source.bottom;\r
+    }\r
+    default:\r
+    {\r
+      return 0;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * @return The distance from the edge furthest in the given direction\r
+ *   of source to the edge nearest in the given direction of dest.\r
+ *   If the dest is not in the direction from source, return 0.\r
+ */\r
+static int MajorAxisDistance(Dali::Toolkit::Control::KeyboardFocus::Direction direction, Dali::Rect<float> source, Dali::Rect<float> dest)\r
+{\r
+  return std::max(0, MajorAxisDistanceRaw(direction, source, dest));\r
+}\r
+\r
+static int MajorAxisDistanceToFarEdgeRaw(Dali::Toolkit::Control::KeyboardFocus::Direction direction, Dali::Rect<float> source, Dali::Rect<float> dest)\r
+{\r
+  switch(direction)\r
+  {\r
+    case Dali::Toolkit::Control::KeyboardFocus::LEFT:\r
+    {\r
+      return source.left - dest.left;\r
+    }\r
+    case Dali::Toolkit::Control::KeyboardFocus::RIGHT:\r
+    {\r
+      return dest.right - source.right;\r
+    }\r
+    case Dali::Toolkit::Control::KeyboardFocus::UP:\r
+    {\r
+      return source.top - dest.top;\r
+    }\r
+    case Dali::Toolkit::Control::KeyboardFocus::DOWN:\r
+    {\r
+      return dest.bottom - source.bottom;\r
+    }\r
+    default:\r
+    {\r
+      return 0;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * @return The distance along the major axis w.r.t the direction from the\r
+ *   edge of source to the far edge of dest.\r
+ *   If the dest is not in the direction from source, return 1\r
+ */\r
+static int MajorAxisDistanceToFarEdge(Dali::Toolkit::Control::KeyboardFocus::Direction direction, Dali::Rect<float> source, Dali::Rect<float> dest)\r
+{\r
+  return std::max(1, MajorAxisDistanceToFarEdgeRaw(direction, source, dest));\r
+}\r
+\r
+/**\r
+ * Find the distance on the minor axis w.r.t the direction to the nearest\r
+ * edge of the destination rectangle.\r
+ * @param direction the direction (up, down, left, right)\r
+ * @param source The source rect.\r
+ * @param dest The destination rect.\r
+ * @return The distance.\r
+ */\r
+static int MinorAxisDistance(Dali::Toolkit::Control::KeyboardFocus::Direction direction, Dali::Rect<float> source, Dali::Rect<float> dest)\r
+{\r
+  switch(direction)\r
+  {\r
+    case Dali::Toolkit::Control::KeyboardFocus::LEFT:\r
+    case Dali::Toolkit::Control::KeyboardFocus::RIGHT:\r
+    {\r
+      // the distance between the center verticals\r
+      return std::abs(\r
+        (((source.top + source.bottom) * 0.5f) -\r
+         (((dest.top + dest.bottom) * 0.5f))));\r
+    }\r
+    case Dali::Toolkit::Control::KeyboardFocus::UP:\r
+    case Dali::Toolkit::Control::KeyboardFocus::DOWN:\r
+    {\r
+      // the distance between the center horizontals\r
+      return std::abs(\r
+        (((source.left + source.right) * 0.5f) -\r
+         (((dest.left + dest.right) * 0.5f))));\r
+    }\r
+    default:\r
+    {\r
+      return 0;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Calculate distance given major and minor axis distances.\r
+ * @param majorAxisDistance The majorAxisDistance\r
+ * @param minorAxisDistance The minorAxisDistance\r
+ * @return The distance\r
+ */\r
+static int GetWeightedDistanceFor(int majorAxisDistance, int minorAxisDistance)\r
+{\r
+  return 13 * majorAxisDistance * majorAxisDistance + minorAxisDistance * minorAxisDistance;\r
+}\r
+\r
+/**\r
+ * Convert x,y,width,height coordinates into left, right, bottom, top coordinates.\r
+ * @param[in,out] rect The rect\r
+ */\r
+static void ConvertCoordinate(Dali::Rect<float>& rect)\r
+{\r
+  // convert x, y, width, height -> left, right, bottom, top\r
+  float left   = rect.x;\r
+  float right  = rect.x + rect.width;\r
+  float bottom = rect.y + rect.height;\r
+  float top    = rect.y;\r
+\r
+  rect.left   = left;\r
+  rect.right  = right;\r
+  rect.bottom = bottom;\r
+  rect.top    = top;\r
+}\r
+\r
+/**\r
+ * Is destRect a candidate for the next focus given the direction?\r
+ * @param srcRect The source rect.\r
+ * @param destRect The dest rect.\r
+ * @param direction The direction (up, down, left, right)\r
+ * @return Whether destRect is a candidate.\r
+ */\r
+static bool IsCandidate(Dali::Rect<float> srcRect, Dali::Rect<float> destRect, Dali::Toolkit::Control::KeyboardFocus::Direction direction)\r
+{\r
+  switch(direction)\r
+  {\r
+    case Dali::Toolkit::Control::KeyboardFocus::LEFT:\r
+    {\r
+      return (srcRect.right > destRect.right || srcRect.left >= destRect.right) && srcRect.left > destRect.left;\r
+    }\r
+    case Dali::Toolkit::Control::KeyboardFocus::RIGHT:\r
+    {\r
+      return (srcRect.left < destRect.left || srcRect.right <= destRect.left) && srcRect.right < destRect.right;\r
+    }\r
+    case Dali::Toolkit::Control::KeyboardFocus::UP:\r
+    {\r
+      return (srcRect.bottom > destRect.bottom || srcRect.top >= destRect.bottom) && srcRect.top > destRect.top;\r
+    }\r
+    case Dali::Toolkit::Control::KeyboardFocus::DOWN:\r
+    {\r
+      return (srcRect.top < destRect.top || srcRect.bottom <= destRect.top) && srcRect.bottom < destRect.bottom;\r
+    }\r
+    default:\r
+    {\r
+      return false;\r
+    }\r
+  }\r
+  return false;\r
+}\r
+\r
+/**\r
+ * Is dest in a given direction from src?\r
+ * @param direction the direction (up, down, left, right)\r
+ * @param src The source rect\r
+ * @param dest The dest rect\r
+ */\r
+static bool IsToDirectionOf(Dali::Toolkit::Control::KeyboardFocus::Direction direction, Dali::Rect<float> src, Dali::Rect<float> dest)\r
+{\r
+  switch(direction)\r
+  {\r
+    case Dali::Toolkit::Control::KeyboardFocus::LEFT:\r
+    {\r
+      return src.left >= dest.right;\r
+    }\r
+    case Dali::Toolkit::Control::KeyboardFocus::RIGHT:\r
+    {\r
+      return src.right <= dest.left;\r
+    }\r
+    case Dali::Toolkit::Control::KeyboardFocus::UP:\r
+    {\r
+      return src.top >= dest.bottom;\r
+    }\r
+    case Dali::Toolkit::Control::KeyboardFocus::DOWN:\r
+    {\r
+      return src.bottom <= dest.top;\r
+    }\r
+    default:\r
+    {\r
+      return false;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Do the given direction's axis of rect1 and rect2 overlap?\r
+ * @param direction the direction (up, down, left, right)\r
+ * @param rect1 The first rect\r
+ * @param rect2 The second rect\r
+ * @return whether the beams overlap\r
+ */\r
+static bool BeamsOverlap(Dali::Toolkit::Control::KeyboardFocus::Direction direction, Dali::Rect<float> rect1, Dali::Rect<float> rect2)\r
+{\r
+  switch(direction)\r
+  {\r
+    case Dali::Toolkit::Control::KeyboardFocus::LEFT:\r
+    case Dali::Toolkit::Control::KeyboardFocus::RIGHT:\r
+    {\r
+      return (rect2.bottom >= rect1.top) && (rect2.top <= rect1.bottom);\r
+    }\r
+    case Dali::Toolkit::Control::KeyboardFocus::UP:\r
+    case Dali::Toolkit::Control::KeyboardFocus::DOWN:\r
+    {\r
+      return (rect2.right >= rect1.left) && (rect2.left <= rect1.right);\r
+    }\r
+    default:\r
+    {\r
+      return false;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * One rectangle may be another candidate than another by virtue of being exclusively in the beam of the source rect.\r
+ * @param direction The direction (up, down, left, right)\r
+ * @param source The source rect\r
+ * @param rect1 The first rect\r
+ * @param rect2 The second rect\r
+ * @return Whether rect1 is a better candidate than rect2 by virtue of it being in src's beam\r
+ */\r
+static bool BeamBeats(Dali::Toolkit::Control::KeyboardFocus::Direction direction, Dali::Rect<float> source, Dali::Rect<float> rect1, Dali::Rect<float> rect2)\r
+{\r
+  const bool rect1InSrcBeam = BeamsOverlap(direction, source, rect1);\r
+  const bool rect2InSrcBeam = BeamsOverlap(direction, source, rect2);\r
+  // if rect1 isn't exclusively in the src beam, it doesn't win\r
+  if(rect2InSrcBeam || !rect1InSrcBeam)\r
+  {\r
+    return false;\r
+  }\r
+  // we know rect1 is in the beam, and rect2 is not\r
+  // if rect1 is to the direction of, and rect2 is not, rect1 wins.\r
+  // for example, for direction left, if rect1 is to the left of the source\r
+  // and rect2 is below, then we always prefer the in beam rect1, since rect2\r
+  // could be reached by going down.\r
+  if(!IsToDirectionOf(direction, source, rect2))\r
+  {\r
+    return true;\r
+  }\r
+  // for horizontal directions, being exclusively in beam always wins\r
+  if((direction == Dali::Toolkit::Control::KeyboardFocus::LEFT || direction == Dali::Toolkit::Control::KeyboardFocus::RIGHT))\r
+  {\r
+    return true;\r
+  }\r
+  // for vertical directions, beams only beat up to a point:\r
+  // now, as long as rect2 isn't completely closer, rect1 wins\r
+  // e.g for direction down, completely closer means for rect2's top\r
+  // edge to be closer to the source's top edge than rect1's bottom edge.\r
+  return (MajorAxisDistance(direction, source, rect1) < MajorAxisDistanceToFarEdge(direction, source, rect2));\r
+}\r
+\r
+} // unnamed namespace\r
+\r
+namespace Dali\r
+{\r
+namespace Toolkit\r
+{\r
+namespace Internal\r
+{\r
+FocusFinder::FocusFinder()\r
+{\r
+}\r
+\r
+FocusFinder::~FocusFinder()\r
+{\r
+}\r
+\r
+Actor FocusFinder::GetNearestFocusableActor(Actor& focusedActor, Toolkit::Control::KeyboardFocus::Direction direction)\r
+{\r
+  Actor nearestActor;\r
+  if(!focusedActor)\r
+  {\r
+    return nearestActor;\r
+  }\r
+\r
+  Rect<float> focusedRect = DevelActor::CalculateScreenExtents(focusedActor);\r
+\r
+  // initialize the best candidate to something impossible\r
+  // (so the first plausible actor will become the best choice)\r
+  Rect<float> bestCandidateRect = focusedRect;\r
+  switch(direction)\r
+  {\r
+    case Toolkit::Control::KeyboardFocus::LEFT:\r
+    {\r
+      bestCandidateRect.x += 1;\r
+      break;\r
+    }\r
+    case Toolkit::Control::KeyboardFocus::RIGHT:\r
+    {\r
+      bestCandidateRect.x -= 1;\r
+      break;\r
+    }\r
+    case Toolkit::Control::KeyboardFocus::UP:\r
+    {\r
+      bestCandidateRect.y += 1;\r
+      break;\r
+    }\r
+    case Toolkit::Control::KeyboardFocus::DOWN:\r
+    {\r
+      bestCandidateRect.y -= 1;\r
+      break;\r
+    }\r
+    default:\r
+    {\r
+      break;\r
+    }\r
+  }\r
+\r
+  ConvertCoordinate(bestCandidateRect);\r
+\r
+  ConvertCoordinate(focusedRect);\r
+\r
+  Integration::SceneHolder window = Integration::SceneHolder::Get(focusedActor);\r
+  if(window)\r
+  {\r
+    Actor rootActor = window.GetRootLayer();\r
+    nearestActor    = FindNextFocus(rootActor, focusedActor, focusedRect, bestCandidateRect, direction);\r
+  }\r
+  return nearestActor;\r
+}\r
+\r
+Actor FocusFinder::FindNextFocus(Actor& actor, Actor& focusedActor, Rect<float>& focusedRect, Rect<float>& bestCandidateRect, Toolkit::Control::KeyboardFocus::Direction direction)\r
+{\r
+  Actor nearestActor;\r
+  if(actor)\r
+  {\r
+    // Recursively children\r
+    const auto childCount = actor.GetChildCount();\r
+    for(auto i = 0u; i < childCount; ++i)\r
+    {\r
+      Dali::Actor child = actor.GetChildAt(i);\r
+      if(child && child != focusedActor && child.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))\r
+      {\r
+        Rect<float> candidateRect = DevelActor::CalculateScreenExtents(child);\r
+\r
+        // convert x, y, width, height -> left, right, bottom, top\r
+        ConvertCoordinate(candidateRect);\r
+\r
+        if(IsBetterCandidate(direction, focusedRect, candidateRect, bestCandidateRect))\r
+        {\r
+          bestCandidateRect = candidateRect;\r
+          nearestActor      = child;\r
+        }\r
+      }\r
+      Actor nextActor = FindNextFocus(child, focusedActor, focusedRect, bestCandidateRect, direction);\r
+      if(nextActor)\r
+      {\r
+        nearestActor = nextActor;\r
+      }\r
+    }\r
+  }\r
+  return nearestActor;\r
+}\r
+\r
+bool FocusFinder::IsBetterCandidate(Toolkit::Control::KeyboardFocus::Direction direction, Rect<float>& focusedRect, Rect<float>& candidateRect, Rect<float>& bestCandidateRect) const\r
+{\r
+  // to be a better candidate, need to at least be a candidate in the first place\r
+  if(!IsCandidate(focusedRect, candidateRect, direction))\r
+  {\r
+    return false;\r
+  }\r
+  // we know that candidateRect is a candidate.. if bestCandidateRect is not a candidate,\r
+  // candidateRect is better\r
+  if(!IsCandidate(focusedRect, bestCandidateRect, direction))\r
+  {\r
+    return true;\r
+  }\r
+  // if candidateRect is better by beam, it wins\r
+  if(BeamBeats(direction, focusedRect, candidateRect, bestCandidateRect))\r
+  {\r
+    return true;\r
+  }\r
+  // if bestCandidateRect is better, then candidateRect cant' be :)\r
+  if(BeamBeats(direction, focusedRect, bestCandidateRect, candidateRect))\r
+  {\r
+    return false;\r
+  }\r
+\r
+  // otherwise, do fudge-tastic comparison of the major and minor axis\r
+  return (GetWeightedDistanceFor(\r
+            MajorAxisDistance(direction, focusedRect, candidateRect),\r
+            MinorAxisDistance(direction, focusedRect, candidateRect)) < GetWeightedDistanceFor(MajorAxisDistance(direction, focusedRect, bestCandidateRect),\r
+                                                                                               MinorAxisDistance(direction, focusedRect, bestCandidateRect)));\r
+}\r
+\r
+} // namespace Internal\r
+\r
+} // namespace Toolkit\r
+\r
+} // namespace Dali\r
diff --git a/dali-toolkit/internal/focus-manager/focus-finder-impl.h b/dali-toolkit/internal/focus-manager/focus-finder-impl.h
new file mode 100644 (file)
index 0000000..012b1aa
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef DALI_TOOLKIT_INTERNAL_FOCUS_FINDER_H\r
+#define DALI_TOOLKIT_INTERNAL_FOCUS_FINDER_H\r
+\r
+/*\r
+ * Copyright (c) 2021 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/object/base-object.h>\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali-toolkit/devel-api/focus-manager/focus-finder.h>\r
+\r
+namespace Dali\r
+{\r
+namespace Integration\r
+{\r
+class SceneHolder;\r
+\r
+} // namespace Integration\r
+\r
+namespace Toolkit\r
+{\r
+namespace Internal\r
+{\r
+class FocusFinder;\r
+\r
+/**\r
+ * @copydoc Toolkit::FocusFinder\r
+ */\r
+class FocusFinder : public Dali::BaseObject\r
+{\r
+public:\r
+  /**\r
+   * Construct a new FocusFinder.\r
+   */\r
+  FocusFinder();\r
+\r
+  /**\r
+   * @copydoc Toolkit::GetNearestFocusableActor\r
+   */\r
+  Actor GetNearestFocusableActor(Actor& focusedActor, Toolkit::Control::KeyboardFocus::Direction direction);\r
+\r
+protected:\r
+  /**\r
+   * Destructor\r
+   */\r
+  virtual ~FocusFinder();\r
+\r
+private:\r
+  /**\r
+   * Find the next actor to take focus in root's descendants, starting from the actor.\r
+   * @param[in] actor The root actor.\r
+   * @param[in] focusedActor The current focused actor.\r
+   * @param[in] focusedRect The rect of current focused actor.\r
+   * @param[in] bestCandidateRect The current best candidate.\r
+   * @param[in] direction The direction.\r
+   * @return nearest Actor.\r
+   */\r
+  Actor FindNextFocus(Actor& actor, Actor& focusedActor, Rect<float>& focusedRect, Rect<float>& bestCandidateRect, Toolkit::Control::KeyboardFocus::Direction direction);\r
+\r
+  /**\r
+   * Is rect1 a better candidate than rect2 for a focus search in a particular\r
+   * direction from a source rect?  This is the core routine that determines\r
+   * the order of focus searching.\r
+   * @param direction The direction (up, down, left, right)\r
+   * @param candidateRect The candidate rectangle\r
+   * @param bestCandidateRect The current best candidate.\r
+   * @return Whether the candidate is the new best.\r
+   */\r
+  bool IsBetterCandidate(Toolkit::Control::KeyboardFocus::Direction direction, Rect<float>& focusedRect, Rect<float>& candidateRect, Rect<float>& bestCandidateRect) const;\r
+\r
+private:\r
+  // Undefined\r
+  FocusFinder(const FocusFinder&);\r
+\r
+  FocusFinder& operator=(const FocusFinder& rhs);\r
+};\r
+\r
+} // namespace Internal\r
+\r
+inline Internal::FocusFinder& GetImpl(Dali::Toolkit::FocusFinder& obj)\r
+{\r
+  DALI_ASSERT_ALWAYS(obj);\r
+\r
+  Dali::BaseObject& handle = obj.GetBaseObject();\r
+\r
+  return static_cast<Internal::FocusFinder&>(handle);\r
+}\r
+\r
+inline const Internal::FocusFinder& GetImpl(const Dali::Toolkit::FocusFinder& obj)\r
+{\r
+  DALI_ASSERT_ALWAYS(obj);\r
+\r
+  const Dali::BaseObject& handle = obj.GetBaseObject();\r
+\r
+  return static_cast<const Internal::FocusFinder&>(handle);\r
+}\r
+\r
+} // namespace Toolkit\r
+\r
+} // namespace Dali\r
+\r
+#endif // DALI_TOOLKIT_INTERNAL_FOCUS_FINDER_H\r
index 0d7bbfd..b06edea 100644 (file)
@@ -36,6 +36,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/focus-manager/focus-finder.h>
 #include <dali-toolkit/devel-api/styling/style-manager-devel.h>
 #include <dali-toolkit/public-api/controls/control-impl.h>
 #include <dali-toolkit/public-api/controls/control.h>
@@ -495,6 +496,11 @@ bool KeyboardFocusManager::MoveFocus(Toolkit::Control::KeyboardFocus::Direction
         nextFocusableActor                  = mPreFocusChangeSignal.Emit(currentFocusActor, Actor(), direction);
         mIsWaitingKeyboardFocusChangeCommit = false;
       }
+      else
+      {
+        // We should find it among the actors nearby.
+        nextFocusableActor = Toolkit::FocusFinder::Get().GetNearestFocusableActor(currentFocusActor, direction);
+      }
     }
 
     if(nextFocusableActor && nextFocusableActor.GetProperty<bool>(Actor::Property::KEYBOARD_FOCUSABLE))
diff --git a/dali-toolkit/internal/graphics/shaders/color-visual-blur-edge-shader.frag b/dali-toolkit/internal/graphics/shaders/color-visual-blur-edge-shader.frag
deleted file mode 100644 (file)
index a3bb80a..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-INPUT mediump vec2 vPosition;
-INPUT mediump vec2 vRectSize;
-INPUT mediump vec2 vOptRectSize;
-INPUT mediump vec4 vCornerRadius;
-
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-uniform mediump float blurRadius;
-
-void main()
-{
-  OUT_COLOR = vec4(mixColor, 1.0) * uColor;
-  if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
-  {
-    return;
-  }
-
-  mediump float radius =
-  mix(
-    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
-    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
-    sign(vPosition.y) * 0.5 + 0.5
-  );
-
-  mediump vec2 v = abs(vPosition) - vRectSize + radius;
-  mediump float cy = radius + blurRadius;
-  mediump float cr = radius + blurRadius;
-
-  cy = min(cy, min(vRectSize.x, vRectSize.y) - radius);
-  v = vec2(min(v.x, v.y), max(v.x, v.y));
-  v = v + cy;
-
-  mediump float blur = 1.0;
-  mediump float potential = 0.0;
-  mediump float alias = min(radius, 1.0);
-  mediump float potentialMin = cy + radius - blurRadius - alias;
-  mediump float potentialMax = cy + radius + blurRadius + alias;
-
-  // move center of circles for reduce defact
-  mediump float cyDiff = min(cy, 0.2 * blurRadius);
-  cy -= cyDiff;
-  cr += cyDiff;
-
-  mediump float diffFromBaseline = cy * v.y - (cy + cr) * v.x;
-
-  if(diffFromBaseline > 0.0)
-  {
-    // out of calculation bound.
-    potential = v.y;
-
-    // for anti-alias when blurRaidus = 0.0
-    mediump float heuristicBaselineScale = max(1.0 , cr * (cr + cy));
-    mediump float potentialDiff = min(alias, diffFromBaseline / heuristicBaselineScale);
-    potentialMin += potentialDiff;
-    potentialMax -= potentialDiff;
-  }
-  else
-  {
-    // get some circle centered (x, x) and radius (r = cr / cy * x)
-    // s.t. point v is on that circle
-    // highest point of that circle is (x, x + r) and potential is x + r
-
-    // solve (v.x - x)^2 + (v.y - x)^2 = (cr / cy * x)^2
-
-    mediump float A = (cr * cr - 2.0 * cy * cy);
-    mediump float B = cy * (v.x + v.y);
-    mediump float V = dot(v,v);
-    mediump float D = B * B + A * V;
-    potential = V * (cr + cy) / (sqrt(D) + B);
-  }
-
-  blur = 1.0 - smoothstep(potentialMin, potentialMax, potential);
-  OUT_COLOR.a *= blur;
-}
diff --git a/dali-toolkit/internal/graphics/shaders/color-visual-blur-edge-shader.vert b/dali-toolkit/internal/graphics/shaders/color-visual-blur-edge-shader.vert
deleted file mode 100644 (file)
index 5306aef..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-INPUT mediump vec2 aPosition;
-OUTPUT mediump vec2 vPosition;
-OUTPUT mediump vec2 vRectSize;
-OUTPUT mediump vec2 vOptRectSize;
-OUTPUT mediump vec4 vCornerRadius;
-
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec2 extraSize;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-uniform mediump float blurRadius;
-uniform mediump vec4 cornerRadius;
-uniform mediump float cornerRadiusPolicy;
-
-vec4 ComputeVertexPosition()
-{
-  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;
-  vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
-  mediump float minSize = min( visualSize.x, visualSize.y );
-  vCornerRadius = mix( cornerRadius * minSize, cornerRadius, cornerRadiusPolicy );
-  vCornerRadius = min( vCornerRadius, minSize * 0.5 );
-  vRectSize = visualSize / 2.0;
-  // optimize fragment shader
-  mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
-  vOptRectSize = vRectSize - 0.2929 * maxRadius - 1.0 - blurRadius;
-
-  vPosition = aPosition * (visualSize + 2.0 * blurRadius);
-  return vec4( vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
-}
-
-void main()
-{
-  gl_Position = uMvpMatrix * ComputeVertexPosition();
-}
diff --git a/dali-toolkit/internal/graphics/shaders/color-visual-rounded-corner-shader.frag b/dali-toolkit/internal/graphics/shaders/color-visual-rounded-corner-shader.frag
deleted file mode 100644 (file)
index 811dc1d..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-INPUT mediump vec2 vPosition;
-INPUT mediump vec2 vRectSize;
-INPUT mediump vec2 vOptRectSize;
-INPUT mediump vec4 vCornerRadius;
-
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-
-void main()
-{
-  OUT_COLOR = vec4(mixColor, 1.0) * uColor;
-  if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
-  {
-    return;
-  }
-  mediump float radius =
-  mix(
-    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
-    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
-    sign(vPosition.y) * 0.5 + 0.5
-  );
-
-  mediump vec2 diff = abs(vPosition) - vRectSize + radius;
-  mediump float dist = length(max(diff, vec2(0.0))) - radius;
-  if(dist > 1.0)
-  {
-    OUT_COLOR.a = 0.0;
-  }
-  else if(dist > -1.0)
-  {
-    if(min(diff.x, diff.y) < 0.0)
-    {
-      dist += min(diff.x, diff.y) / max(radius, 1.0);
-    }
-    OUT_COLOR.a *= 1.0 - smoothstep(-1.0, 1.0, dist);
-  }
-}
diff --git a/dali-toolkit/internal/graphics/shaders/color-visual-rounded-corner-shader.vert b/dali-toolkit/internal/graphics/shaders/color-visual-rounded-corner-shader.vert
deleted file mode 100644 (file)
index 0a6a257..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-INPUT mediump vec2 aPosition;
-OUTPUT mediump vec2 vPosition;
-OUTPUT mediump vec2 vRectSize;
-OUTPUT mediump vec2 vOptRectSize;
-OUTPUT mediump vec4 vCornerRadius;
-
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec2 extraSize;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-uniform mediump vec4 cornerRadius;
-uniform mediump float cornerRadiusPolicy;
-
-vec4 ComputeVertexPosition()
-{
-  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;
-  vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
-  mediump float minSize = min( visualSize.x, visualSize.y );
-  vCornerRadius = mix( cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
-  vCornerRadius = min( vCornerRadius, minSize * 0.5 );
-  vRectSize = visualSize / 2.0;
-  // optimize fragment shader
-  mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
-  vOptRectSize = vRectSize - 0.2929 * maxRadius - 1.0;
-  vPosition = aPosition* visualSize;
-  return vec4( vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
-}
-
-void main()
-{
-  gl_Position = uMvpMatrix * ComputeVertexPosition();
-}
index fef045b..bf93629 100644 (file)
@@ -1,7 +1,265 @@
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+#ifndef IS_REQUIRED_BLUR
+#define IS_REQUIRED_BLUR 0
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE || IS_REQUIRED_BLUR
+INPUT mediump vec2 vPosition;
+INPUT mediump vec2 vRectSize;
+INPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+INPUT mediump vec4 vCornerRadius;
+#endif
+#endif
+
 uniform lowp vec4 uColor;
 uniform lowp vec3 mixColor;
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+uniform lowp vec4 borderlineColor;
+#endif
+#if IS_REQUIRED_BLUR
+uniform mediump float blurRadius;
+#endif
+
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE || IS_REQUIRED_BLUR
+// Global values both rounded corner and borderline use
+
+// radius of rounded corner on this quadrant
+mediump float gRadius = 0.0;
+
+// fragment coordinate. NOTE : vec2(0.0, 0.0) is vRectSize, the corner of visual
+mediump vec2 gFragmentPosition = vec2(0.0, 0.0);
+// center coordinate of rounded corner circle. vec2(gCenterPosition, gCenterPosition).
+mediump float gCenterPosition = 0.0;
+// relative coordinate of gFragmentPosition from gCenterPosition.
+mediump vec2 gDiff = vec2(0.0, 0.0);
+// potential value what our algorithm use.
+mediump float gPotential = 0.0;
+
+// threshold of potential
+mediump float gPotentialRange = 0.0;
+mediump float gMaxOutlinePotential = 0.0;
+mediump float gMinOutlinePotential = 0.0;
+mediump float gMaxInlinePotential = 0.0;
+mediump float gMinInlinePotential = 0.0;
+
+void calculateCornerRadius()
+{
+#if IS_REQUIRED_ROUNDED_CORNER
+  gRadius =
+  mix(
+    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
+    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
+    sign(vPosition.y) * 0.5 + 0.5
+  );
+#endif
+}
+
+void calculatePosition()
+{
+  gFragmentPosition = abs(vPosition) - vRectSize;
+  gCenterPosition = -gRadius;
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+  gCenterPosition += borderlineWidth * (clamp(borderlineOffset, -1.0, 1.0) + 1.0) * 0.5;
+#endif
+  gDiff = gFragmentPosition - gCenterPosition;
+}
+
+void calculatePotential()
+{
+  gPotential = length(max(gDiff, 0.0)) + min(0.0, max(gDiff.x, gDiff.y));
+}
+
+void setupMinMaxPotential()
+{
+  gPotentialRange = 1.0;
+
+  gMaxOutlinePotential = gRadius + gPotentialRange;
+  gMinOutlinePotential = gRadius - gPotentialRange;
+
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+  gMaxInlinePotential = gMaxOutlinePotential - borderlineWidth;
+  gMinInlinePotential = gMinOutlinePotential - borderlineWidth;
+#else
+  gMaxInlinePotential = gMaxOutlinePotential;
+  gMinInlinePotential = gMinOutlinePotential;
+#endif
+
+  // reduce defect near edge of rounded corner.
+  gMaxOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+  gMinOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+}
+
+void PreprocessPotential()
+{
+  calculateCornerRadius();
+  calculatePosition();
+  calculatePotential();
+
+  setupMinMaxPotential();
+}
+#endif
+
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
+{
+  mediump float potential = gPotential;
+
+  // default opacity of borderline is 0.0
+  mediump float borderlineOpacity = 0.0;
+
+  // calculate borderline opacity by potential
+  if(potential > gMinInlinePotential)
+  {
+    // potential is inside borderline range.
+    borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
+  }
+
+  //calculate inside of borderline when outilneColor.a < 1.0
+  if(borderlineColor.a < 1.0)
+  {
+    mediump float tCornerRadius = -gCenterPosition;
+    mediump float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
+    mediump float MinTexturelinePotential = tCornerRadius - gPotentialRange;
+    if(potential > MaxTexturelinePotential)
+    {
+      // potential is out of texture range. use borderline color instead of texture
+      textureColor = vec4(borderlineColor.xyz, 0.0);
+    }
+    else if(potential > MinTexturelinePotential)
+    {
+      // potential is in texture range
+      textureColor = mix(textureColor, vec4(borderlineColor.xyz, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+    }
+    borderlineOpacity *= borderlineColor.a;
+  }
+  return mix(textureColor, vec4(borderlineColor.xyz, 1.0), borderlineOpacity);
+}
+#endif
+
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_ROUNDED_CORNER
+mediump float calculateCornerOpacity()
+{
+  mediump float potential = gPotential;
+
+  // default opacity is 1.0
+  mediump float opacity = 1.0;
+
+  // calculate borderline opacity by potential
+  if(potential > gMaxOutlinePotential)
+  {
+    // potential is out of borderline range
+    opacity = 0.0;
+  }
+  else if(potential > gMinOutlinePotential)
+  {
+    opacity = 1.0 - smoothstep(gMinOutlinePotential, gMaxOutlinePotential, potential);
+  }
+  return opacity;
+}
+#endif
+
+#if IS_REQUIRED_BLUR
+mediump float calculateBlurOpacity()
+{
+// Don't use borderline!
+  mediump vec2 v = gDiff;
+  mediump float cy = gRadius + blurRadius;
+  mediump float cr = gRadius + blurRadius;
+
+#if IS_REQUIRED_ROUNDED_CORNER
+  // This routine make perfect circle. If corner radius is not exist, we don't consider prefect circle.
+  cy = min(cy, min(vRectSize.x, vRectSize.y) - gRadius);
+#endif
+  v = vec2(min(v.x, v.y), max(v.x, v.y));
+  v = v + cy;
+
+  mediump float potential = 0.0;
+  mediump float alias = min(gRadius, 1.0);
+  mediump float potentialMin = cy + gRadius - blurRadius - alias;
+  mediump float potentialMax = cy + gRadius + blurRadius + alias;
+
+  // move center of circles for reduce defact
+  mediump float cyDiff = min(cy, 0.2 * blurRadius);
+  cy -= cyDiff;
+  cr += cyDiff;
+
+  mediump float diffFromBaseline = cy * v.y - (cy + cr) * v.x;
+
+  if(diffFromBaseline > 0.0)
+  {
+    // out of calculation bound.
+    potential = v.y;
+
+    // for anti-alias when blurRaidus = 0.0
+    mediump float heuristicBaselineScale = max(1.0 , cr * (cr + cy));
+    mediump float potentialDiff = min(alias, diffFromBaseline / heuristicBaselineScale);
+    potentialMin += potentialDiff;
+    potentialMax -= potentialDiff;
+  }
+  else
+  {
+    // get some circle centered (x, x) and radius (r = cr / cy * x)
+    // s.t. point v is on that circle
+    // highest point of that circle is (x, x + r) and potential is x + r
+
+    // solve (v.x - x)^2 + (v.y - x)^2 = (cr / cy * x)^2
+#if IS_REQUIRED_ROUNDED_CORNER
+    // NOTE : lowspec HW cannot calculate here. need to reduce numeric error
+    mediump float A = (cr * cr - 2.0 * cy * cy);
+    mediump float B = cy * (v.x + v.y);
+    mediump float V = dot(v,v);
+    mediump float D = B * B + A * V;
+    potential = V * (cr + cy) / (sqrt(D) + B);
+#else
+    // We can simplify this value cause cy = 0.8 * blurRadius, cr = 1.2 * blurRadius
+    // potential = 5.0*(sqrt(4.0*(v.x+v.y)^2 + dot(v,v)) - 2.0*(v.x+v.y));
+    //           = 10.0*(v.x+v.y) * (sqrt(1.0 + (length(v) / (2.0*(v.x+v.y)))^2) - 1.0);
+    //           = 10.0*(v.x+v.y) * (sqrt(1.25 - x + x^2) - 1.0);
+    //          ~= 10.0*(v.x+v.y) * (0.11803399 - 0.44721360x + 0.35777088x^2 - 0.14310x^3 + O(x^4)) (Taylor series)
+    //          ~= -1.0557281 * (v.x + v.y) + 2.236068 * length(v) - ~~~ (here, x <= 0.5 * (1.0 - sqrt(0.5)) < 0.1464467)
+    // Note : This simplify need cause we should use it on lowspec HW.
+    mediump float x = 0.5 * (1.0 - length(v) / (v.x + v.y));
+    potential = -1.0557281 * (v.x + v.y) + 2.236068 * length(v) + 10.0 * (v.x + v.y) * (0.35777088 - 0.14310 * x) * x * x;
+#endif
+  }
+
+  return 1.0 - smoothstep(potentialMin, potentialMax, potential);
+}
+#endif
 
 void main()
 {
-  OUT_COLOR = vec4(mixColor, 1.0) * uColor;
-}
\ No newline at end of file
+  lowp vec4 targetColor = vec4(mixColor, 1.0) * uColor;
+
+#if IS_REQUIRED_BLUR || IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+  // skip most potential calculate for performance
+  if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
+  {
+    OUT_COLOR = targetColor;
+    return;
+  }
+  PreprocessPotential();
+#endif
+
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+  targetColor = convertBorderlineColor(targetColor);
+#endif
+  OUT_COLOR = targetColor;
+
+#if IS_REQUIRED_BLUR
+  mediump float opacity = calculateBlurOpacity();
+  OUT_COLOR.a *= opacity;
+#elif IS_REQUIRED_ROUNDED_CORNER
+  mediump float opacity = calculateCornerOpacity();
+  OUT_COLOR.a *= opacity;
+#endif
+}
index 993d9d4..2798185 100644 (file)
@@ -1,4 +1,22 @@
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+#ifndef IS_REQUIRED_BLUR
+#define IS_REQUIRED_BLUR 0
+#endif
+
 INPUT mediump vec2 aPosition;
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE || IS_REQUIRED_BLUR
+OUTPUT mediump vec2 vPosition;
+OUTPUT mediump vec2 vRectSize;
+OUTPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+OUTPUT mediump vec4 vCornerRadius;
+#endif
+#endif
 
 uniform highp mat4 uMvpMatrix;
 uniform highp vec3 uSize;
@@ -9,16 +27,57 @@ uniform highp vec2 size;
 uniform mediump vec4 offsetSizeMode;
 uniform mediump vec2 origin;
 uniform mediump vec2 anchorPoint;
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+#endif
+#if IS_REQUIRED_BLUR
+uniform mediump float blurRadius;
+#endif
+#if IS_REQUIRED_ROUNDED_CORNER
+uniform mediump vec4 cornerRadius;
+uniform mediump float cornerRadiusPolicy;
+#endif
 uniform mediump vec2 extraSize;
 
 vec4 ComputeVertexPosition()
 {
   vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;
-  vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
-  return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
+  vec2 visualOffset = mix(offset, offset/uSize.xy, offsetSizeMode.xy);
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE || IS_REQUIRED_BLUR
+  vRectSize = visualSize * 0.5;
+  vOptRectSize = vRectSize;
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER
+#if !IS_REQUIRED_BLUR && IS_REQUIRED_BORDERLINE
+  mediump float minSize = min(visualSize.x, visualSize.y) + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth;
+#else
+  mediump float minSize = min(visualSize.x, visualSize.y);
+#endif
+  vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
+  vCornerRadius = min(vCornerRadius, minSize * 0.5);
+  // Optimize fragment shader. 0.2929 ~= 1.0 - sqrt(0.5)
+  mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
+  vOptRectSize -= 0.2929 * maxRadius + 1.0;
+#endif
+
+#if IS_REQUIRED_BLUR
+  vPosition = aPosition * (visualSize + 2.0 * blurRadius);
+  vOptRectSize -= blurRadius + 1.0;
+#elif IS_REQUIRED_BORDERLINE
+  vPosition = aPosition * (visualSize + (1.0 + clamp(borderlineOffset, -1.0, 1.0))* borderlineWidth);
+  vOptRectSize -= (1.0 - clamp(borderlineOffset, -1.0, 1.0)) * 0.5 * borderlineWidth + 1.0;
+#elif IS_REQUIRED_ROUNDED_CORNER
+  vPosition = aPosition * visualSize;
+#else
+  mediump vec2 vPosition = aPosition * visualSize;
+#endif
+  return vec4(vPosition + anchorPoint * visualSize + (visualOffset + origin) * uSize.xy, 0.0, 1.0);
 }
 
 void main()
 {
   gl_Position = uMvpMatrix * ComputeVertexPosition();
-}
\ No newline at end of file
+}
diff --git a/dali-toolkit/internal/graphics/shaders/glyphy-common-glsl-shader.def b/dali-toolkit/internal/graphics/shaders/glyphy-common-glsl-shader.def
new file mode 100644 (file)
index 0000000..f044a16
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the \"License\");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an \"AS IS\" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+
+#ifndef GLYPHY_INFINITY
+#define GLYPHY_INFINITY 1e9
+#endif
+#ifndef GLYPHY_EPSILON
+#define GLYPHY_EPSILON  1e-5
+#endif
+
+#ifndef GLYPHY_RGBA
+#ifdef GLYPHY_BGRA
+#define GLYPHY_RGBA(v) glyphy_bgra (v)
+#else
+#define GLYPHY_RGBA(v) glyphy_rgba (v)
+#endif
+#endif
+
+vec4 glyphy_rgba (const vec4 v)
+{
+  return v.rgba;
+}
+
+vec4 glyphy_bgra (const vec4 v)
+{
+  return v.bgra;
+}
+
+struct glyphy_arc_t
+{
+  vec2  p0;
+  vec2  p1;
+  float d;
+};
+
+struct glyphy_arc_endpoint_t
+{
+  /* Second arc endpoint */
+  vec2  p;
+  /* Infinity if this endpoint does not form an arc with the previous
+   * endpoint.  Ie. a \"move_to\".  Test with glyphy_isinf().
+   * Arc depth otherwise.  */
+  float d;
+};
+
+struct glyphy_arc_list_t
+{
+  /* Number of endpoints in the list.
+   * Will be zero if we're far away inside or outside, in which case side is set.
+   * Will be -1 if this arc-list encodes a single line, in which case line_* are set. */
+  int num_endpoints;
+
+  /* If num_endpoints is zero, this specifies whether we are inside (-1)
+   * or outside (+1).  Otherwise we're unsure (0). */
+  int side;
+  /* Offset to the arc-endpoints from the beginning of the glyph blob */
+  int offset;
+
+  /* A single line is all we care about.  It's right here. */
+  float line_angle;
+  float line_distance; /* From nominal glyph center */
+};
+
+bool glyphy_isinf (const float v)
+{
+  return abs (v) >= GLYPHY_INFINITY * .5;
+}
+
+bool glyphy_iszero (const float v)
+{
+  return abs (v) <= GLYPHY_EPSILON * 2.;
+}
+
+vec2 glyphy_ortho (const vec2 v)
+{
+  return vec2 (-v.y, v.x);
+}
+
+int glyphy_float_to_byte (const float v)
+{
+  return int (v * (256. - GLYPHY_EPSILON));
+}
+
+ivec4 glyphy_vec4_to_bytes (const vec4 v)
+{
+  return ivec4 (v * (256. - GLYPHY_EPSILON));
+}
+
+ivec2 glyphy_float_to_two_nimbles (const float v)
+{
+  int f = glyphy_float_to_byte (v);
+  return ivec2 (f / 16, int(mod (float(f), 16.)));
+}
+
+/* returns tan (2 * atan (d)) */
+float glyphy_tan2atan (const float d)
+{
+  return 2. * d / (1. - d * d);
+}
+
+glyphy_arc_endpoint_t glyphy_arc_endpoint_decode(const vec4 v, const ivec2 nominal_size)
+{
+  vec2 p = (vec2 (glyphy_float_to_two_nimbles (v.a)) + v.gb) / 16.;
+  float d = v.r;
+  if (d == 0.)
+    d = GLYPHY_INFINITY;
+  else
+#define GLYPHY_MAX_D .5
+    d = float(glyphy_float_to_byte (d) - 128) * GLYPHY_MAX_D / 127.;
+#undef GLYPHY_MAX_D
+  return glyphy_arc_endpoint_t (p * vec2(nominal_size), d);
+}
+
+vec2 glyphy_arc_center (const glyphy_arc_t a)
+{
+  return mix (a.p0, a.p1, .5) +
+        glyphy_ortho (a.p1 - a.p0) / (2. * glyphy_tan2atan (a.d));
+}
+
+bool glyphy_arc_wedge_contains (const glyphy_arc_t a, const vec2 p)
+{
+  float d2 = glyphy_tan2atan (a.d);
+  return dot (p - a.p0, (a.p1 - a.p0) * mat2(1,  d2, -d2, 1)) >= 0. &&
+        dot (p - a.p1, (a.p1 - a.p0) * mat2(1, -d2,  d2, 1)) <= 0.;
+}
+
+float glyphy_arc_wedge_signed_dist_shallow (const glyphy_arc_t a, const vec2 p)
+{
+  vec2 v = normalize (a.p1 - a.p0);
+  float line_d = dot (p - a.p0, glyphy_ortho (v));
+  if (a.d == 0.)
+    return line_d;
+
+  float d0 = dot ((p - a.p0), v);
+  if (d0 < 0.)
+    return sign (line_d) * distance (p, a.p0);
+  float d1 = dot ((a.p1 - p), v);
+  if (d1 < 0.)
+    return sign (line_d) * distance (p, a.p1);
+  float r = 2. * a.d * (d0 * d1) / (d0 + d1);
+  if (r * line_d > 0.)
+    return sign (line_d) * min (abs (line_d + r), min (distance (p, a.p0), distance (p, a.p1)));
+  return line_d + r;
+}
+
+float glyphy_arc_wedge_signed_dist (const glyphy_arc_t a, const vec2 p)
+{
+  if (abs (a.d) <= .03)
+    return glyphy_arc_wedge_signed_dist_shallow (a, p);
+  vec2 c = glyphy_arc_center (a);
+  return sign (a.d) * (distance (a.p0, c) - distance (p, c));
+}
+
+float glyphy_arc_extended_dist (const glyphy_arc_t a, const vec2 p)
+{
+  /* Note: this doesn't handle points inside the wedge. */
+  vec2 m = mix (a.p0, a.p1, .5);
+  float d2 = glyphy_tan2atan (a.d);
+  if (dot (p - m, a.p1 - m) < 0.)
+    return dot (p - a.p0, normalize ((a.p1 - a.p0) * mat2(+d2, -1, +1, +d2)));
+  else
+    return dot (p - a.p1, normalize ((a.p1 - a.p0) * mat2(-d2, -1, +1, -d2)));
+}
+
+int glyphy_arc_list_offset (const vec2 p, const ivec2 nominal_size)
+{
+  ivec2 cell = ivec2 (clamp (floor (p), vec2 (0.,0.), vec2(nominal_size - 1)));
+  return cell.y * nominal_size.x + cell.x;
+}
+
+glyphy_arc_list_t glyphy_arc_list_decode (const vec4 v, const ivec2 nominal_size)
+{
+  glyphy_arc_list_t l;
+  ivec4 iv = glyphy_vec4_to_bytes (v);
+  l.side = 0; /* unsure */
+  if (iv.r == 0)
+  { /* arc-list encoded */
+    l.offset = (iv.g * 256) + iv.b;
+    l.num_endpoints = iv.a;
+    if (l.num_endpoints == 255)
+    {
+      l.num_endpoints = 0;
+      l.side = -1;
+    }
+    else if (l.num_endpoints == 0)
+      l.side = +1;
+  }
+  else
+  { /* single line encoded */
+    l.num_endpoints = -1;
+    l.line_distance = ( float(iv.r)/32. + 0.01*float(iv.g)/82.0 - 6.) * max (float (nominal_size.x), float (nominal_size.y));
+    l.line_angle = ( -float(iv.b)/40.74 - float( iv.a )*0.0001 )-3.142;
+  }
+  return l;
+}
diff --git a/dali-toolkit/internal/graphics/shaders/glyphy-sdf-glsl-shader.def b/dali-toolkit/internal/graphics/shaders/glyphy-sdf-glsl-shader.def
new file mode 100644 (file)
index 0000000..2b5accd
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the \"License\");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an \"AS IS\" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+#ifndef GLYPHY_TEXTURE1D_FUNC
+#define GLYPHY_TEXTURE1D_FUNC glyphy_texture1D_func
+#endif
+#ifndef GLYPHY_TEXTURE1D_EXTRA_DECLS
+#define GLYPHY_TEXTURE1D_EXTRA_DECLS
+#endif
+#ifndef GLYPHY_TEXTURE1D_EXTRA_ARGS
+#define GLYPHY_TEXTURE1D_EXTRA_ARGS
+#endif
+
+#ifndef GLYPHY_SDF_TEXTURE1D_FUNC
+#define GLYPHY_SDF_TEXTURE1D_FUNC GLYPHY_TEXTURE1D_FUNC
+#endif
+#ifndef GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS
+#define GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS GLYPHY_TEXTURE1D_EXTRA_DECLS
+#endif
+#ifndef GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS
+#define GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS GLYPHY_TEXTURE1D_EXTRA_ARGS
+#endif
+#ifndef GLYPHY_SDF_TEXTURE1D
+#define GLYPHY_SDF_TEXTURE1D(offset) GLYPHY_RGBA(GLYPHY_SDF_TEXTURE1D_FUNC (offset GLYPHY_TEXTURE1D_EXTRA_ARGS))
+#endif
+
+#ifndef GLYPHY_MAX_NUM_ENDPOINTS
+#define GLYPHY_MAX_NUM_ENDPOINTS 32
+#endif
+
+glyphy_arc_list_t glyphy_arc_list (const vec2 p, const ivec2 nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS)
+{
+  int cell_offset = glyphy_arc_list_offset (p, nominal_size);
+  vec4 arc_list_data = GLYPHY_SDF_TEXTURE1D (cell_offset);
+  return glyphy_arc_list_decode (arc_list_data, nominal_size);
+}
+
+float glyphy_sdf (const vec2 p, const ivec2 nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS)
+{
+  glyphy_arc_list_t arc_list = glyphy_arc_list (p, nominal_size  GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS);
+
+  /* Short-circuits */
+  if (arc_list.num_endpoints == 0)
+  {
+    /* far-away cell */
+    return GLYPHY_INFINITY * float(arc_list.side);
+  }
+  if (arc_list.num_endpoints == -1)
+  {
+    /* single-line */
+    float angle = arc_list.line_angle;
+    vec2 n = vec2 (cos (angle), sin (angle));
+    return dot (p - (vec2(nominal_size) * .5), n) - arc_list.line_distance;
+  }
+
+  float side = float(arc_list.side);
+  float min_dist = GLYPHY_INFINITY;
+  glyphy_arc_t closest_arc;
+
+  glyphy_arc_endpoint_t endpoint_prev, endpoint;
+  endpoint_prev = glyphy_arc_endpoint_decode (GLYPHY_SDF_TEXTURE1D (arc_list.offset), nominal_size);
+  for (int i = 1; i < GLYPHY_MAX_NUM_ENDPOINTS; i++)
+  {
+    if (i >= arc_list.num_endpoints)
+    {
+      break;
+    }
+    endpoint = glyphy_arc_endpoint_decode (GLYPHY_SDF_TEXTURE1D (arc_list.offset + i), nominal_size);
+    glyphy_arc_t a = glyphy_arc_t (endpoint_prev.p, endpoint.p, endpoint.d);
+    endpoint_prev = endpoint;
+    if (glyphy_isinf (a.d)) continue;
+
+    if (glyphy_arc_wedge_contains (a, p))
+    {
+      float sdist = glyphy_arc_wedge_signed_dist (a, p);
+      float udist = abs (sdist) * (1. - GLYPHY_EPSILON);
+      if (udist <= min_dist)
+      {
+        min_dist = udist;
+        side = sign (sdist);
+      }
+    }
+    else
+    {
+      float udist = min (distance (p, a.p0), distance (p, a.p1));
+      if (udist < min_dist)
+      {
+        min_dist = udist;
+        side = 0.; /* unsure */
+        closest_arc = a;
+      }
+      else if (side == 0. && udist == min_dist)
+      {
+        /* If this new distance is the same as the current minimum,
+         * compare extended distances.  Take the sign from the arc
+         * with larger extended distance. */
+        float old_ext_dist = glyphy_arc_extended_dist (closest_arc, p);
+        float new_ext_dist = glyphy_arc_extended_dist (a, p);
+
+        float ext_dist = abs (new_ext_dist) <= abs (old_ext_dist) ?
+                         old_ext_dist : new_ext_dist;
+
+#ifdef GLYPHY_SDF_PSEUDO_DISTANCE
+        /* For emboldening and stuff: */
+        min_dist = abs (ext_dist);
+#endif
+        side = sign (ext_dist);
+      }
+    }
+  }
+
+  if (side == 0.)
+  {
+    // Technically speaking this should not happen, but it does.  So try to fix it.
+    float ext_dist = glyphy_arc_extended_dist (closest_arc, p);
+    side = sign (ext_dist);
+  }
+
+  return min_dist * side;
+}
+
+float glyphy_point_dist (const vec2 p, const ivec2 nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS)
+{
+  glyphy_arc_list_t arc_list = glyphy_arc_list (p, nominal_size  GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS);
+
+  float side = float(arc_list.side);
+  float min_dist = GLYPHY_INFINITY;
+
+  if (arc_list.num_endpoints == 0)
+    return min_dist;
+
+  glyphy_arc_endpoint_t endpoint;
+  for (int i = 0; i < GLYPHY_MAX_NUM_ENDPOINTS; i++)
+  {
+    if (i >= arc_list.num_endpoints)
+    {
+      break;
+    }
+    endpoint = glyphy_arc_endpoint_decode (GLYPHY_SDF_TEXTURE1D (arc_list.offset + i), nominal_size);
+    if (glyphy_isinf (endpoint.d)) continue;
+    min_dist = min (min_dist, distance (p, endpoint.p));
+  }
+
+  return min_dist;
+}
diff --git a/dali-toolkit/internal/graphics/shaders/glyphy-shader-extention-prefix.def b/dali-toolkit/internal/graphics/shaders/glyphy-shader-extention-prefix.def
new file mode 100644 (file)
index 0000000..3f7237d
--- /dev/null
@@ -0,0 +1,3 @@
+#extension GL_OES_standard_derivatives : enable
+precision highp float;
+precision highp int;
diff --git a/dali-toolkit/internal/graphics/shaders/glyphy-shader-fragment-prefix.frag b/dali-toolkit/internal/graphics/shaders/glyphy-shader-fragment-prefix.frag
new file mode 100644 (file)
index 0000000..4cb1423
--- /dev/null
@@ -0,0 +1,34 @@
+struct Material
+{
+  mediump float mOpacity;
+  mediump float mShininess;
+  lowp    vec4  mAmbient;
+  lowp    vec4  mDiffuse;
+  lowp    vec4  mSpecular;
+  lowp    vec4  mEmissive;
+};
+
+uniform sampler2D     sTexture;
+uniform sampler2D     sOpacityTexture;
+uniform sampler2D     sNormalMapTexture;
+uniform sampler2D     sEffect;
+varying mediump vec2 vTexCoord;
+uniform Material      uMaterial;
+uniform lowp  vec4    uColor;
+varying highp vec4    vVertex;
+varying highp vec3    vNormal;
+varying mediump vec4  vColor;
+uniform vec4 u_atlas_info;
+
+#define GLYPHY_TEXTURE1D_EXTRA_DECLS , sampler2D _tex, ivec4 _atlas_info, ivec2 _atlas_pos
+#define GLYPHY_TEXTURE1D_EXTRA_ARGS , _tex, _atlas_info, _atlas_pos
+#define GLYPHY_DEMO_EXTRA_ARGS , sTexture, uu_atlas_info, gi.atlas_pos
+
+vec4 glyphy_texture1D_func (int offset GLYPHY_TEXTURE1D_EXTRA_DECLS)
+{
+  ivec2 item_geom = _atlas_info.zw;
+  vec2 pos = (vec2 (_atlas_pos.xy * item_geom +
+                    ivec2 (mod (float (offset), float (item_geom.x)), offset / item_geom.x)) +
+             + vec2 (.5, .5)) / vec2(_atlas_info.xy);
+  return texture2D (_tex, pos);
+}
diff --git a/dali-toolkit/internal/graphics/shaders/glyphy-shader-main.frag b/dali-toolkit/internal/graphics/shaders/glyphy-shader-main.frag
new file mode 100644 (file)
index 0000000..4fc43da
--- /dev/null
@@ -0,0 +1,66 @@
+uniform float u_contrast;
+uniform float u_gamma_adjust;
+uniform float u_outline_thickness;
+uniform float u_outline;
+uniform float u_boldness;
+
+varying vec4 v_glyph;
+
+#define SQRT2_2 0.70711 /* 1 / sqrt(2.) */
+#define SQRT2   1.41421
+
+struct glyph_info_t
+{
+  ivec2 nominal_size;
+  ivec2 atlas_pos;
+};
+
+glyph_info_t glyph_info_decode (vec4 v)
+{
+  glyph_info_t gi;
+  gi.nominal_size = (ivec2 (mod (v.zw, 256.)) + 2) / 4;
+  gi.atlas_pos = ivec2 (v_glyph.zw) / 256;
+  return gi;
+}
+
+
+float antialias (float d)
+{
+  return smoothstep (-.75, +.75, d);
+}
+
+vec4 source_over (const vec4 src, const vec4 dst)
+{
+  // http://dev.w3.org/fxtf/compositing-1/#porterduffcompositingoperators_srcover
+  float alpha = src.a + (dst.a * (1. - src.a));
+  return vec4 (((src.rgb * src.a) + (dst.rgb * dst.a * (1. - src.a))) / alpha, alpha);
+}
+
+void main()
+{
+  vec2 p = v_glyph.xy;
+  glyph_info_t gi = glyph_info_decode (v_glyph);
+
+  /* isotropic antialiasing */
+  vec2 dpdx = dFdx (p);
+  vec2 dpdy = dFdy (p);
+  float m = length (vec2 (length (dpdx), length (dpdy))) * SQRT2_2;
+
+  vec4 color = vec4( vColor.rgb * uColor.rgb, vColor.a * uColor.a );
+
+  ivec4 uu_atlas_info = ivec4( u_atlas_info );
+  float gsdist = glyphy_sdf (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);
+  float sdist = gsdist / m * u_contrast;
+
+  sdist -= u_boldness * 10.;
+  if ( glyphy_iszero( u_outline ) )
+    sdist = abs (sdist) - u_outline_thickness * .5;
+  if (sdist > 1.)
+    discard;
+  float alpha = antialias (-sdist);
+  if (u_gamma_adjust != 1.)
+    alpha = pow (alpha, 1./u_gamma_adjust);
+  color = vec4 (color.rgb,color.a * alpha);
+
+  gl_FragColor = color;
+}
diff --git a/dali-toolkit/internal/graphics/shaders/glyphy-shader-main.vert b/dali-toolkit/internal/graphics/shaders/glyphy-shader-main.vert
new file mode 100644 (file)
index 0000000..9b0f342
--- /dev/null
@@ -0,0 +1,31 @@
+uniform   mediump mat4    uProjection;
+uniform   mediump mat4    uModelView;
+uniform   mediump mat4    uMvpMatrix;
+uniform           bool    uTextureMapped;
+uniform   mediump vec4    uCustomTextureCoords;
+attribute highp   vec2    aTexCoord;
+varying   mediump vec2    vTexCoord;
+uniform   mat3            uModelViewIT;
+attribute mediump vec3    aNormal;
+varying   mediump vec3    vNormal;
+attribute mediump vec2    aPosition;
+varying   mediump vec4    vVertex;
+attribute mediump vec4    aColor;
+varying   mediump vec4    vColor;
+varying vec4 v_glyph;
+
+vec4 glyph_vertex_transcode (vec2 v)
+{
+  ivec2 g = ivec2 (v);
+  ivec2 corner = ivec2 (mod (v, 2.));
+  g /= 2;
+  ivec2 nominal_size = ivec2 (mod (vec2(g), 64.));
+  return vec4 (corner * nominal_size, g * 4);
+}
+
+void main()
+{
+  gl_Position = uMvpMatrix * vec4 (aPosition, 0.0, 1.0);
+  v_glyph = glyph_vertex_transcode (aTexCoord);
+  vColor = aColor;
+}
\ No newline at end of file
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-bounding-box-rounded-corner-shader.vert b/dali-toolkit/internal/graphics/shaders/gradient-visual-bounding-box-rounded-corner-shader.vert
deleted file mode 100644 (file)
index bd08a63..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-attribute mediump vec2 aPosition;
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-uniform mediump mat3 uAlignmentMatrix;
-varying mediump vec2 vTexCoord;
-varying mediump vec2 vPosition;
-varying mediump vec2 vRectSize;
-varying mediump vec2 vOptRectSize;
-varying mediump vec4 vCornerRadius;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-uniform mediump vec4 cornerRadius;
-uniform mediump float cornerRadiusPolicy;
-
-vec4 ComputeVertexPosition()
-{
-  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw);
-  vec2 visualOffset = mix(offset, offset/uSize.xy, offsetSizeMode.xy);
-  mediump float minSize = min(visualSize.x, visualSize.y);
-  vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
-  vCornerRadius = min(vCornerRadius, minSize * 0.5);
-  vRectSize = visualSize * 0.5;
-  // Optimize fragment shader
-  mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
-  vOptRectSize = vRectSize - 0.2929 * maxRadius - 1.0;
-  vPosition = aPosition * visualSize;
-  return vec4((aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0);
-}
-
-void main()
-{
-  mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
-  vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
-
-  gl_Position = uMvpMatrix * ComputeVertexPosition();
-}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-bounding-box-shader.vert b/dali-toolkit/internal/graphics/shaders/gradient-visual-bounding-box-shader.vert
deleted file mode 100644 (file)
index 018e260..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-attribute mediump vec2 aPosition;
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-uniform mediump mat3 uAlignmentMatrix;
-varying mediump vec2 vTexCoord;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp 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()
-{
-  mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
-  vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
-
-  gl_Position = uMvpMatrix * ComputeVertexPosition();
-}
\ No newline at end of file
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-linear-rounded-corner-shader.frag b/dali-toolkit/internal/graphics/shaders/gradient-visual-linear-rounded-corner-shader.frag
deleted file mode 100644 (file)
index 1b29ae0..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-uniform sampler2D sTexture; // sampler1D?
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-varying mediump vec2 vTexCoord;
-varying mediump vec2 vPosition;
-varying mediump vec2 vRectSize;
-varying mediump vec2 vOptRectSize;
-varying mediump vec4 vCornerRadius;
-
-void main()
-{
-  gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * vec4(mixColor, 1.0) * uColor;
-  if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
-  {
-    return;
-  }
-  mediump float radius =
-  mix(
-    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
-    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
-    sign(vPosition.y) * 0.5 + 0.5
-  );
-
-  mediump vec2 diff = abs(vPosition) - vRectSize + radius;
-  mediump float dist = length(max(diff, vec2(0.0))) - radius;
-  if(dist > 1.0)
-  {
-    gl_FragColor = vec4(0.0);
-  }
-  else if(dist > -1.0)
-  {
-    if(min(diff.x, diff.y) < 0.0)
-    {
-      dist += min(diff.x, diff.y) / max(radius, 1.0);
-    }
-    gl_FragColor *= 1.0 - smoothstep(-1.0, 1.0, dist);
-  }
-}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-linear-shader.frag b/dali-toolkit/internal/graphics/shaders/gradient-visual-linear-shader.frag
deleted file mode 100644 (file)
index 1ec04b2..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-uniform sampler2D sTexture; // sampler1D?
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-varying mediump vec2 vTexCoord;
-
-void main()
-{
-  gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * vec4(mixColor, 1.0) * uColor;
-}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-radial-rounded-corner-shader.frag b/dali-toolkit/internal/graphics/shaders/gradient-visual-radial-rounded-corner-shader.frag
deleted file mode 100644 (file)
index 68df0c5..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-uniform sampler2D sTexture; // sampler1D?
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-varying mediump vec2 vTexCoord;
-varying mediump vec2 vPosition;
-varying mediump vec2 vRectSize;
-varying mediump vec2 vOptRectSize;
-varying mediump vec4 vCornerRadius;
-
-void main()
-{
-  gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * vec4(mixColor, 1.0) * uColor;
-  if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
-  {
-    return;
-  }
-  mediump float radius =
-  mix(
-    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
-    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
-    sign(vPosition.y) * 0.5 + 0.5
-  );
-
-  mediump vec2 diff = abs(vPosition) - vRectSize + radius;
-  mediump float dist = length(max(diff, vec2(0.0))) - radius;
-  if(dist > 1.0)
-  {
-    gl_FragColor = vec4(0.0);
-  }
-  else if(dist > -1.0)
-  {
-    if(min(diff.x, diff.y) < 0.0)
-    {
-      dist += min(diff.x, diff.y) / max(radius, 1.0);
-    }
-    gl_FragColor *= 1.0 - smoothstep(-1.0, 1.0, dist);
-  }
-}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-radial-shader.frag b/dali-toolkit/internal/graphics/shaders/gradient-visual-radial-shader.frag
deleted file mode 100644 (file)
index 8d37383..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-uniform sampler2D sTexture; // sampler1D?
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-varying mediump vec2 vTexCoord;
-
-void main()
-{
-  gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * vec4(mixColor, 1.0) * uColor;
-}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-shader.frag b/dali-toolkit/internal/graphics/shaders/gradient-visual-shader.frag
new file mode 100644 (file)
index 0000000..305ff92
--- /dev/null
@@ -0,0 +1,196 @@
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+#ifndef RADIAL
+#define RADIAL 0
+#endif
+
+INPUT mediump vec2 vTexCoord;
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+INPUT mediump vec2 vPosition;
+INPUT mediump vec2 vRectSize;
+INPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+INPUT mediump vec4 vCornerRadius;
+#endif
+#endif
+
+uniform sampler2D sTexture; // sampler1D?
+uniform lowp vec4 uColor;
+uniform lowp vec3 mixColor;
+#if IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+uniform lowp vec4 borderlineColor;
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+// Global values both rounded corner and borderline use
+
+// radius of rounded corner on this quadrant
+mediump float gRadius = 0.0;
+
+// fragment coordinate. NOTE : vec2(0.0, 0.0) is vRectSize, the corner of visual
+mediump vec2 gFragmentPosition = vec2(0.0, 0.0);
+// center coordinate of rounded corner circle. vec2(gCenterPosition, gCenterPosition).
+mediump float gCenterPosition = 0.0;
+// relative coordinate of gFragmentPosition from gCenterPosition.
+mediump vec2 gDiff = vec2(0.0, 0.0);
+// potential value what our algorithm use.
+mediump float gPotential = 0.0;
+
+// threshold of potential
+mediump float gPotentialRange = 0.0;
+mediump float gMaxOutlinePotential = 0.0;
+mediump float gMinOutlinePotential = 0.0;
+mediump float gMaxInlinePotential = 0.0;
+mediump float gMinInlinePotential = 0.0;
+
+void calculateCornerRadius()
+{
+#if IS_REQUIRED_ROUNDED_CORNER
+  gRadius =
+  mix(
+    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
+    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
+    sign(vPosition.y) * 0.5 + 0.5
+  );
+#endif
+}
+
+void calculatePosition()
+{
+  gFragmentPosition = abs(vPosition) - vRectSize;
+  gCenterPosition = -gRadius;
+#if IS_REQUIRED_BORDERLINE
+  gCenterPosition += borderlineWidth * (clamp(borderlineOffset, -1.0, 1.0) + 1.0) * 0.5;
+#endif
+  gDiff = gFragmentPosition - gCenterPosition;
+}
+
+void calculatePotential()
+{
+  gPotential = length(max(gDiff, 0.0)) + min(0.0, max(gDiff.x, gDiff.y));
+}
+
+void setupMinMaxPotential()
+{
+  gPotentialRange = 1.0;
+
+  gMaxOutlinePotential = gRadius + gPotentialRange;
+  gMinOutlinePotential = gRadius - gPotentialRange;
+
+#if IS_REQUIRED_BORDERLINE
+  gMaxInlinePotential = gMaxOutlinePotential - borderlineWidth;
+  gMinInlinePotential = gMinOutlinePotential - borderlineWidth;
+#else
+  gMaxInlinePotential = gMaxOutlinePotential;
+  gMinInlinePotential = gMinOutlinePotential;
+#endif
+
+  // reduce defect near edge of rounded corner.
+  gMaxOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+  gMinOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+}
+
+void PreprocessPotential()
+{
+  calculateCornerRadius();
+  calculatePosition();
+  calculatePotential();
+
+  setupMinMaxPotential();
+}
+#endif
+
+
+#if IS_REQUIRED_BORDERLINE
+lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
+{
+  mediump float potential = gPotential;
+
+  // default opacity of borderline is 0.0
+  mediump float borderlineOpacity = 0.0;
+
+  // calculate borderline opacity by potential
+  if(potential > gMinInlinePotential)
+  {
+    // potential is inside borderline range.
+    borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
+  }
+
+  //calculate inside of borderline when outilneColor.a < 1.0
+  if(borderlineColor.a < 1.0)
+  {
+    mediump float tCornerRadius = -gCenterPosition;
+    mediump float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
+    mediump float MinTexturelinePotential = tCornerRadius - gPotentialRange;
+    if(potential > MaxTexturelinePotential)
+    {
+      // potential is out of texture range. use borderline color instead of texture
+      textureColor = vec4(borderlineColor.xyz, 0.0);
+    }
+    else if(potential > MinTexturelinePotential)
+    {
+      // potential is in texture range
+      textureColor = mix(textureColor, vec4(borderlineColor.xyz, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+    }
+    borderlineOpacity *= borderlineColor.a;
+  }
+  return mix(textureColor, vec4(borderlineColor.xyz, 1.0), borderlineOpacity);
+}
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER
+mediump float calculateCornerOpacity()
+{
+  mediump float potential = gPotential;
+
+  // default opacity is 1.0
+  mediump float opacity = 1.0;
+
+  // calculate borderline opacity by potential
+  if(potential > gMaxOutlinePotential)
+  {
+    // potential is out of borderline range
+    opacity = 0.0;
+  }
+  else if(potential > gMinOutlinePotential)
+  {
+    opacity = 1.0 - smoothstep(gMinOutlinePotential, gMaxOutlinePotential, potential);
+  }
+  return opacity;
+}
+#endif
+
+void main()
+{
+#if RADIAL
+  lowp vec4 textureColor = TEXTURE(sTexture, vec2(length(vTexCoord), 0.5)) * vec4(mixColor, 1.0) * uColor;
+#else
+  lowp vec4 textureColor = TEXTURE(sTexture, vec2(vTexCoord.y, 0.5)) * vec4(mixColor, 1.0) * uColor;
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+  // skip most potential calculate for performance
+  if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
+  {
+    OUT_COLOR = textureColor;
+    return;
+  }
+  PreprocessPotential();
+#endif
+
+#if IS_REQUIRED_BORDERLINE
+  textureColor = convertBorderlineColor(textureColor);
+#endif
+  OUT_COLOR = textureColor;
+
+#if IS_REQUIRED_ROUNDED_CORNER
+  mediump float opacity = calculateCornerOpacity();
+  OUT_COLOR *= opacity;
+#endif
+}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-shader.vert b/dali-toolkit/internal/graphics/shaders/gradient-visual-shader.vert
new file mode 100644 (file)
index 0000000..f9e80fe
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+#ifndef USER_SPACE
+#define USER_SPACE 0
+#endif
+
+INPUT mediump vec2 aPosition;
+OUTPUT mediump vec2 vTexCoord;
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+OUTPUT mediump vec2 vPosition;
+OUTPUT mediump vec2 vRectSize;
+OUTPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+OUTPUT mediump vec4 vCornerRadius;
+#endif
+#endif
+
+uniform highp mat4 uMvpMatrix;
+uniform highp vec3 uSize;
+uniform mediump mat3 uAlignmentMatrix;
+
+//Visual size and offset
+uniform mediump vec2 offset;
+uniform highp vec2 size;
+uniform mediump vec4 offsetSizeMode;
+uniform mediump vec2 origin;
+uniform mediump vec2 anchorPoint;
+#if IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+#endif
+#if IS_REQUIRED_ROUNDED_CORNER
+uniform mediump vec4 cornerRadius;
+uniform mediump float cornerRadiusPolicy;
+#endif
+
+vec4 ComputeVertexPosition()
+{
+  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );
+  vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+  vRectSize = visualSize * 0.5;
+  vOptRectSize = vRectSize;
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER
+#if IS_REQUIRED_BORDERLINE
+  mediump float minSize = min(visualSize.x, visualSize.y) + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth;
+#else
+  mediump float minSize = min(visualSize.x, visualSize.y);
+#endif
+  vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
+  vCornerRadius = min(vCornerRadius, minSize * 0.5);
+  // Optimize fragment shader. 0.2929 ~= 1.0 - sqrt(0.5)
+  mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
+  vOptRectSize -= 0.2929 * maxRadius + 1.0;
+#endif
+
+#if IS_REQUIRED_BORDERLINE
+  vPosition = aPosition * (visualSize + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth);
+  vOptRectSize -= (1.0 - clamp(borderlineOffset, -1.0, 1.0)) * 0.5 * borderlineWidth + 1.0;
+#elif IS_REQUIRED_ROUNDED_CORNER
+  vPosition = aPosition * visualSize;
+#else
+  mediump vec2 vPosition = aPosition * visualSize;
+#endif
+
+  return vec4(vPosition + anchorPoint * visualSize + (visualOffset + origin) * uSize.xy, 0.0, 1.0);
+}
+
+void main()
+{
+  mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
+  gl_Position = uMvpMatrix * ComputeVertexPosition();
+#if USER_SPACE
+  vertexPosition.xyz *= uSize;
+#endif
+  vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
+}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-user-space-rounded-corner-shader.vert b/dali-toolkit/internal/graphics/shaders/gradient-visual-user-space-rounded-corner-shader.vert
deleted file mode 100644 (file)
index 23ded26..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-attribute mediump vec2 aPosition;
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-uniform mediump mat3 uAlignmentMatrix;
-varying mediump vec2 vTexCoord;
-varying mediump vec2 vPosition;
-varying mediump vec2 vRectSize;
-varying mediump vec2 vOptRectSize;
-varying mediump vec4 vCornerRadius;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-uniform mediump vec4 cornerRadius;
-uniform mediump float cornerRadiusPolicy;
-
-vec4 ComputeVertexPosition()
-{
-  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw);
-  vec2 visualOffset = mix(offset, offset/uSize.xy, offsetSizeMode.xy);
-  mediump float minSize = min(visualSize.x, visualSize.y);
-  vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
-  vCornerRadius = min(vCornerRadius, minSize * 0.5);
-  vRectSize = visualSize * 0.5;
-  // Optimze fragment shader
-  mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
-  vOptRectSize = vRectSize - 0.2929 * maxRadius - 1.0;
-  vCornerRadius = max(vCornerRadius, 1.0);
-  vPosition = aPosition * visualSize;
-  return vec4((aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0);
-}
-
-void main()
-{
-  mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
-  vertexPosition.xyz *= uSize;
-  gl_Position = uMvpMatrix * ComputeVertexPosition();
-
-  vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
-}
diff --git a/dali-toolkit/internal/graphics/shaders/gradient-visual-user-space-shader.vert b/dali-toolkit/internal/graphics/shaders/gradient-visual-user-space-shader.vert
deleted file mode 100644 (file)
index ca1eab6..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-attribute mediump vec2 aPosition;
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-uniform mediump mat3 uAlignmentMatrix;
-varying mediump vec2 vTexCoord;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp 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()
-{
-  mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
-  vertexPosition.xyz *= uSize;
-  gl_Position = uMvpMatrix * ComputeVertexPosition();
-
-  vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;
-}
diff --git a/dali-toolkit/internal/graphics/shaders/image-visual-atlas-clamp-shader.frag b/dali-toolkit/internal/graphics/shaders/image-visual-atlas-clamp-shader.frag
deleted file mode 100644 (file)
index 0d87f9d..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-INPUT mediump vec2 vTexCoord;
-
-uniform sampler2D sTexture;
-uniform mediump vec4 uAtlasRect;
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-uniform lowp float preMultipliedAlpha;
-
-void main()
-{
-  mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );
-  OUT_COLOR = TEXTURE( sTexture, texCoord ) * uColor * vec4( mixColor, 1.0 );
-}
\ No newline at end of file
diff --git a/dali-toolkit/internal/graphics/shaders/image-visual-atlas-various-wrap-shader.frag b/dali-toolkit/internal/graphics/shaders/image-visual-atlas-various-wrap-shader.frag
deleted file mode 100644 (file)
index eeb8a0c..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-INPUT mediump vec2 vTexCoord;
-
-uniform sampler2D sTexture;
-uniform mediump vec4 uAtlasRect;
-
-// WrapMode -- 0: CLAMP; 1: REPEAT; 2: REFLECT;
-uniform lowp vec2 wrapMode;
-
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-uniform lowp float preMultipliedAlpha;
-mediump float wrapCoordinate( mediump vec2 range, mediump float coordinate, lowp float wrap )
-
-{
-  mediump float coord;
-  if( wrap > 1.5 )\n // REFLECT
-    coord = 1.0-abs(fract(coordinate*0.5)*2.0 - 1.0);
-  else \n// warp == 0 or 1
-    coord = mix(coordinate, fract( coordinate ), wrap);
-  return clamp( mix(range.x, range.y, coord), range.x, range.y );
-}
-
-void main()
-{
-  mediump vec2 texCoord = vec2( wrapCoordinate( uAtlasRect.xz, vTexCoord.x, wrapMode.x ),
-                                wrapCoordinate( uAtlasRect.yw, vTexCoord.y, wrapMode.y ) );
-  OUT_COLOR = TEXTURE( sTexture, texCoord ) * uColor * vec4( mixColor, 1.0 );
-}
\ No newline at end of file
diff --git a/dali-toolkit/internal/graphics/shaders/image-visual-no-atlas-shader.frag b/dali-toolkit/internal/graphics/shaders/image-visual-no-atlas-shader.frag
deleted file mode 100644 (file)
index ffc960c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-INPUT mediump vec2 vTexCoord;
-
-uniform sampler2D sTexture;
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-uniform lowp float preMultipliedAlpha;
-
-void main()
-{
-  OUT_COLOR = TEXTURE( sTexture, vTexCoord ) * uColor * vec4( mixColor, 1.0 );
-}
diff --git a/dali-toolkit/internal/graphics/shaders/image-visual-rounded-corner-shader.frag b/dali-toolkit/internal/graphics/shaders/image-visual-rounded-corner-shader.frag
deleted file mode 100644 (file)
index 6eacb93..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-INPUT mediump vec2 vTexCoord;
-INPUT mediump vec2 vPosition;
-INPUT mediump vec2 vRectSize;
-INPUT mediump vec2 vOptRectSize;
-INPUT mediump vec4 vCornerRadius;
-
-uniform sampler2D sTexture;
-uniform lowp vec4 uColor;
-uniform lowp vec3 mixColor;
-uniform lowp float preMultipliedAlpha;
-
-void main()
-{
-  if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
-  {
-    OUT_COLOR = TEXTURE(sTexture, vTexCoord) * uColor * vec4(mixColor, 1.0);
-    return;
-  }
-  mediump float radius =
-  mix(
-    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
-    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
-    sign(vPosition.y) * 0.5 + 0.5
-  );
-
-  mediump vec2 diff = abs(vPosition) - vRectSize + radius;
-  mediump float dist = length(max(diff, vec2(0.0))) - radius;
-  mediump float opacity = 1.0;
-  if(dist > 1.0)
-  {
-    opacity = 0.0;
-  }
-  else if(dist > -1.0)
-  {
-    if(min(diff.x, diff.y) < 0.0)
-    {
-      dist += min(diff.x, diff.y) / max(radius, 1.0);
-    }
-    opacity = 1.0 - smoothstep(-1.0, 1.0, dist);
-  }
-
-  OUT_COLOR = TEXTURE(sTexture, vTexCoord) * uColor * vec4(mixColor, 1.0);
-  OUT_COLOR.a *= opacity;
-  OUT_COLOR.rgb *= mix(1.0, opacity, preMultipliedAlpha);
-}
diff --git a/dali-toolkit/internal/graphics/shaders/image-visual-rounded-corner-shader.vert b/dali-toolkit/internal/graphics/shaders/image-visual-rounded-corner-shader.vert
deleted file mode 100644 (file)
index c35b1b6..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-INPUT mediump vec2 aPosition;
-OUTPUT mediump vec2 vTexCoord;
-OUTPUT mediump vec2 vPosition;
-OUTPUT mediump vec2 vRectSize;
-OUTPUT mediump vec2 vOptRectSize;
-OUTPUT mediump vec4 vCornerRadius;
-
-uniform highp mat4 uMvpMatrix;
-uniform highp vec3 uSize;
-uniform mediump vec4 pixelArea;
-
-//Visual size and offset
-uniform mediump vec2 offset;
-uniform highp vec2 size;
-uniform mediump vec4 offsetSizeMode;
-uniform mediump vec2 origin;
-uniform mediump vec2 anchorPoint;
-uniform mediump vec4 cornerRadius;
-uniform mediump float cornerRadiusPolicy;
-uniform mediump vec2 extraSize;
-
-vec4 ComputeVertexPosition()
-{
-  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw) + extraSize;
-  vec2 visualOffset = mix(offset, offset/uSize.xy, offsetSizeMode.xy);
-  mediump float minSize = min(visualSize.x, visualSize.y);
-  vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
-  vCornerRadius = min(vCornerRadius, minSize * 0.5);
-  vRectSize = visualSize * 0.5;
-  // Optimize fragment shader
-  mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
-  vOptRectSize = vRectSize - 0.2929 * maxRadius - 1.0;
-  vPosition = aPosition* visualSize;
-  return vec4(vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0);
-}
-
-void main()
-{
-  gl_Position = uMvpMatrix * ComputeVertexPosition();
-  vTexCoord = pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5));
-}
diff --git a/dali-toolkit/internal/graphics/shaders/image-visual-shader.frag b/dali-toolkit/internal/graphics/shaders/image-visual-shader.frag
new file mode 100644 (file)
index 0000000..e83d463
--- /dev/null
@@ -0,0 +1,224 @@
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+#ifndef ATLAS_DEFAULT_WARP
+#define ATLAS_DEFAULT_WARP 0
+#endif
+#ifndef ATLAS_CUSTOM_WARP
+#define ATLAS_CUSTOM_WARP 0
+#endif
+
+INPUT mediump vec2 vTexCoord;
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+INPUT mediump vec2 vPosition;
+INPUT mediump vec2 vRectSize;
+INPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+INPUT mediump vec4 vCornerRadius;
+#endif
+#endif
+
+uniform sampler2D sTexture;
+#if ATLAS_DEFAULT_WARP
+uniform mediump vec4 uAtlasRect;
+#elif ATLAS_CUSTOM_WARP
+// WrapMode -- 0: CLAMP; 1: REPEAT; 2: REFLECT;
+uniform lowp vec2 wrapMode;
+#endif
+
+uniform lowp vec4 uColor;
+uniform lowp vec3 mixColor;
+uniform lowp float preMultipliedAlpha;
+#if IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+uniform lowp vec4 borderlineColor;
+#endif
+
+#if ATLAS_CUSTOM_WARP
+mediump float wrapCoordinate( mediump vec2 range, mediump float coordinate, lowp float wrap )
+{
+  mediump float coord;
+  if( wrap > 1.5 ) /* REFLECT */
+    coord = 1.0 - abs(fract(coordinate*0.5)*2.0 - 1.0);
+  else /* warp is 0 or 1 */
+    coord = mix(coordinate, fract(coordinate), wrap);
+  return clamp(mix(range.x, range.y, coord), range.x, range.y);
+}
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+// Global values both rounded corner and borderline use
+
+// radius of rounded corner on this quadrant
+mediump float gRadius = 0.0;
+
+// fragment coordinate. NOTE : vec2(0.0, 0.0) is vRectSize, the corner of visual
+mediump vec2 gFragmentPosition = vec2(0.0, 0.0);
+// center coordinate of rounded corner circle. vec2(gCenterPosition, gCenterPosition).
+mediump float gCenterPosition = 0.0;
+// relative coordinate of gFragmentPosition from gCenterPosition.
+mediump vec2 gDiff = vec2(0.0, 0.0);
+// potential value what our algorithm use.
+mediump float gPotential = 0.0;
+
+// threshold of potential
+mediump float gPotentialRange = 0.0;
+mediump float gMaxOutlinePotential = 0.0;
+mediump float gMinOutlinePotential = 0.0;
+mediump float gMaxInlinePotential = 0.0;
+mediump float gMinInlinePotential = 0.0;
+
+void calculateCornerRadius()
+{
+#if IS_REQUIRED_ROUNDED_CORNER
+  gRadius =
+  mix(
+    mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
+    mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
+    sign(vPosition.y) * 0.5 + 0.5
+  );
+#endif
+}
+
+void calculatePosition()
+{
+  gFragmentPosition = abs(vPosition) - vRectSize;
+  gCenterPosition = -gRadius;
+#if IS_REQUIRED_BORDERLINE
+  gCenterPosition += borderlineWidth * (clamp(borderlineOffset, -1.0, 1.0) + 1.0) * 0.5;
+#endif
+  gDiff = gFragmentPosition - gCenterPosition;
+}
+
+void calculatePotential()
+{
+  gPotential = length(max(gDiff, 0.0)) + min(0.0, max(gDiff.x, gDiff.y));
+}
+
+void setupMinMaxPotential()
+{
+  gPotentialRange = 1.0;
+
+  gMaxOutlinePotential = gRadius + gPotentialRange;
+  gMinOutlinePotential = gRadius - gPotentialRange;
+
+#if IS_REQUIRED_BORDERLINE
+  gMaxInlinePotential = gMaxOutlinePotential - borderlineWidth;
+  gMinInlinePotential = gMinOutlinePotential - borderlineWidth;
+#else
+  gMaxInlinePotential = gMaxOutlinePotential;
+  gMinInlinePotential = gMinOutlinePotential;
+#endif
+
+  // reduce defect near edge of rounded corner.
+  gMaxOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+  gMinOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
+}
+
+void PreprocessPotential()
+{
+  calculateCornerRadius();
+  calculatePosition();
+  calculatePotential();
+
+  setupMinMaxPotential();
+}
+#endif
+
+#if IS_REQUIRED_BORDERLINE
+lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
+{
+  mediump float potential = gPotential;
+
+  // default opacity of borderline is 0.0
+  mediump float borderlineOpacity = 0.0;
+
+  // calculate borderline opacity by potential
+  if(potential > gMinInlinePotential)
+  {
+    // potential is inside borderline range.
+    borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
+  }
+
+  //calculate inside of borderline when outilneColor.a < 1.0
+  if(borderlineColor.a < 1.0)
+  {
+    mediump float tCornerRadius = -gCenterPosition;
+    mediump float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
+    mediump float MinTexturelinePotential = tCornerRadius - gPotentialRange;
+    if(potential > MaxTexturelinePotential)
+    {
+      // potential is out of texture range. use borderline color instead of texture
+      textureColor = vec4(borderlineColor.xyz, 0.0);
+    }
+    else if(potential > MinTexturelinePotential)
+    {
+      // potential is in texture range
+      textureColor = mix(textureColor, vec4(borderlineColor.xyz, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
+    }
+    borderlineOpacity *= borderlineColor.a;
+  }
+  return mix(textureColor, vec4(borderlineColor.xyz, 1.0), borderlineOpacity);
+}
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER
+mediump float calculateCornerOpacity()
+{
+  mediump float potential = gPotential;
+
+  // default opacity is 1.0
+  mediump float opacity = 1.0;
+
+  // calculate borderline opacity by potential
+  if(potential > gMaxOutlinePotential)
+  {
+    // potential is out of borderline range
+    opacity = 0.0;
+  }
+  else if(potential > gMinOutlinePotential)
+  {
+    opacity = 1.0 - smoothstep(gMinOutlinePotential, gMaxOutlinePotential, potential);
+  }
+  return opacity;
+}
+#endif
+
+void main()
+{
+#if ATLAS_DEFAULT_WARP
+  mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );
+#elif ATLAS_CUSTOM_WARP
+  mediump vec2 texCoord = vec2( wrapCoordinate( uAtlasRect.xz, vTexCoord.x, wrapMode.x ),
+                                wrapCoordinate( uAtlasRect.yw, vTexCoord.y, wrapMode.y ) );
+#else
+  mediump vec2 texCoord = vTexCoord;
+#endif
+
+  lowp vec4 textureColor = TEXTURE( sTexture, texCoord ) * uColor * vec4( mixColor, 1.0 );
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+  // skip most potential calculate for performance
+  if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
+  {
+    OUT_COLOR = textureColor;
+    return;
+  }
+  PreprocessPotential();
+#endif
+
+#if IS_REQUIRED_BORDERLINE
+  textureColor = convertBorderlineColor(textureColor);
+#endif
+  OUT_COLOR = textureColor;
+
+#if IS_REQUIRED_ROUNDED_CORNER
+  mediump float opacity = calculateCornerOpacity();
+  OUT_COLOR.a *= opacity;
+  OUT_COLOR.rgb *= mix(1.0, opacity, preMultipliedAlpha);
+#endif
+}
index fe0c35c..21d4084 100644 (file)
@@ -1,5 +1,20 @@
+#ifndef IS_REQUIRED_ROUNDED_CORNER
+#define IS_REQUIRED_ROUNDED_CORNER 0
+#endif
+#ifndef IS_REQUIRED_BORDERLINE
+#define IS_REQUIRED_BORDERLINE 0
+#endif
+
 INPUT mediump vec2 aPosition;
 OUTPUT mediump vec2 vTexCoord;
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+OUTPUT mediump vec2 vPosition;
+OUTPUT mediump vec2 vRectSize;
+OUTPUT mediump vec2 vOptRectSize;
+#if IS_REQUIRED_ROUNDED_CORNER
+OUTPUT mediump vec4 vCornerRadius;
+#endif
+#endif
 
 uniform highp mat4 uMvpMatrix;
 uniform highp vec3 uSize;
@@ -11,17 +26,53 @@ uniform highp vec2 size;
 uniform mediump vec4 offsetSizeMode;
 uniform mediump vec2 origin;
 uniform mediump vec2 anchorPoint;
+#if IS_REQUIRED_BORDERLINE
+uniform mediump float borderlineWidth;
+uniform mediump float borderlineOffset;
+#endif
+#if IS_REQUIRED_ROUNDED_CORNER
+uniform mediump vec4 cornerRadius;
+uniform mediump float cornerRadiusPolicy;
+#endif
 uniform mediump vec2 extraSize;
 
 vec4 ComputeVertexPosition()
 {
-  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;
-  vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);
-  return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
+  vec2 visualSize = mix(uSize.xy * size, size, offsetSizeMode.zw) + extraSize;
+  vec2 visualOffset = mix(offset, offset/uSize.xy, offsetSizeMode.xy);
+
+#if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
+  vRectSize = visualSize * 0.5;
+  vOptRectSize = vRectSize;
+#endif
+
+#if IS_REQUIRED_ROUNDED_CORNER
+#if IS_REQUIRED_BORDERLINE
+  mediump float minSize = min(visualSize.x, visualSize.y) + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth;
+#else
+  mediump float minSize = min(visualSize.x, visualSize.y);
+#endif
+  vCornerRadius = mix(cornerRadius * minSize, cornerRadius, cornerRadiusPolicy);
+  vCornerRadius = min(vCornerRadius, minSize * 0.5);
+  // Optimize fragment shader. 0.2929 ~= 1.0 - sqrt(0.5)
+  mediump float maxRadius = max(max(vCornerRadius.x, vCornerRadius.y), max(vCornerRadius.z, vCornerRadius.w));
+  vOptRectSize -= 0.2929 * maxRadius + 1.0;
+#endif
+
+#if IS_REQUIRED_BORDERLINE
+  vPosition = aPosition * (visualSize + (1.0 + clamp(borderlineOffset, -1.0, 1.0)) * borderlineWidth);
+  vOptRectSize -= (1.0 - clamp(borderlineOffset, -1.0, 1.0)) * 0.5 * borderlineWidth + 1.0;
+#elif IS_REQUIRED_ROUNDED_CORNER
+  vPosition = aPosition * visualSize;
+#else
+  mediump vec2 vPosition = aPosition * visualSize;
+#endif
+
+  vTexCoord = pixelArea.xy + pixelArea.zw * (vPosition.xy / max(vec2(1.0), visualSize) + vec2(0.5));
+  return vec4(vPosition + anchorPoint * visualSize + (visualOffset + origin) * uSize.xy, 0.0, 1.0);
 }
 
 void main()
 {
   gl_Position = uMvpMatrix * ComputeVertexPosition();
-  vTexCoord = pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) );
-}
\ No newline at end of file
+}
diff --git a/dali-toolkit/internal/text/hyphenator.cpp b/dali-toolkit/internal/text/hyphenator.cpp
new file mode 100644 (file)
index 0000000..66f99a3
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/hyphenator.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/hyphenation.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+
+#include <cstring> // for strcmp
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+const char* UTF8 = "UTF-8";
+
+Vector<bool> GetWordHyphens(const Character* word,
+                            Length           wordSize,
+                            const char*      lang)
+{
+  Vector<bool> hyphens;
+
+  if(0u == wordSize || word == nullptr)
+  {
+    // Nothing to do if there are no characters.
+    return hyphens;
+  }
+
+  TextAbstraction::Hyphenation hyphenation = TextAbstraction::Hyphenation::Get();
+
+  // first get the needed encoding
+  std::string text;
+  if(strcmp(hyphenation.GetDictionaryEncoding(lang), UTF8) == 0)
+  {
+    Utf32ToUtf8(word, wordSize, text);
+  }
+  else
+  {
+    text = std::string((char*)word, (size_t)(wordSize * sizeof(Character)));
+  }
+
+  return hyphenation.GetWordHyphens(text.c_str(), (int)text.length(), lang);
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/hyphenator.h b/dali-toolkit/internal/text/hyphenator.h
new file mode 100644 (file)
index 0000000..eef2246
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef DALI_TOOLKIT_TEXT_HYPHENATOR_H
+#define DALI_TOOLKIT_TEXT_HYPHENATOR_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+{
+/**
+ * Gets a vector booleans that indicates possible hyphen locations.
+ *
+ * @param[in] word the word to get possible hyphens for.
+ * @param[in] wordSize the word size in bytes.
+ * @param[in] lang the language for the word
+ *
+ * @return vector of boolean, true if possible to hyphenate at this character position.
+ */
+Vector<bool> GetWordHyphens(const Character* word,
+                            Length           wordSize,
+                            const char*      lang);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_HYPHENATOR_H
index fcf5f5e..25f83d1 100644 (file)
@@ -44,11 +44,12 @@ namespace
 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;
-const float              MIN_LINE_SIZE = 0.f;
+const float              MAX_FLOAT      = std::numeric_limits<float>::max();
+const CharacterDirection LTR            = false;
+const CharacterDirection RTL            = !LTR;
+const float              LINE_SPACING   = 0.f;
+const float              MIN_LINE_SIZE  = 0.f;
+const Character          HYPHEN_UNICODE = 0x002D;
 
 inline bool isEmptyLineAtLast(const Vector<LineRun>& lines, const Vector<LineRun>::Iterator& line)
 {
@@ -448,7 +449,11 @@ struct Engine::Impl
     const Length totalNumberOfGlyphs = parameters.textModel->mVisualModel->mGlyphs.Count();
 
     const bool isMultiline   = mLayout == MULTI_LINE_BOX;
-    const bool isWordLaidOut = parameters.textModel->mLineWrapMode == Text::LineWrap::WORD;
+    const bool isWordLaidOut = parameters.textModel->mLineWrapMode == Text::LineWrap::WORD ||
+                               (parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+                               (parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED);
+    const bool isHyphenMode = parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION;
+    const bool isMixedMode  = parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED;
 
     // The last glyph to be laid-out.
     const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
@@ -486,7 +491,10 @@ struct Engine::Impl
     FontId lastFontId = glyphMetrics.fontId;
     UpdateLineHeight(glyphMetrics, tmpLineLayout);
 
-    bool oneWordLaidOut = false;
+    bool       oneWordLaidOut   = false;
+    bool       oneHyphenLaidOut = false;
+    GlyphIndex hyphenIndex      = 0;
+    GlyphInfo  hyphenGlyph;
 
     for(GlyphIndex glyphIndex = lineLayout.glyphIndex;
         glyphIndex < lastGlyphOfParagraphPlusOne;)
@@ -565,7 +573,15 @@ struct Engine::Impl
          (tmpLineLayout.length > parameters.boundingBox.width))
       {
         // Current word does not fit in the box's width.
-        if(!oneWordLaidOut || completelyFill)
+        if(((oneHyphenLaidOut && isHyphenMode) ||
+            (!oneWordLaidOut && isMixedMode && oneHyphenLaidOut)) &&
+           !completelyFill)
+        {
+          parameters.textModel->mVisualModel->mHyphen.glyph.PushBack(hyphenGlyph);
+          parameters.textModel->mVisualModel->mHyphen.index.PushBack(hyphenIndex + 1);
+        }
+
+        if((!oneWordLaidOut && !oneHyphenLaidOut) || completelyFill)
         {
           DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  Break the word by character\n");
 
@@ -608,7 +624,7 @@ struct Engine::Impl
          (TextAbstraction::LINE_MUST_BREAK == lineBreakInfo))
       {
         LineLayout currentLineLayout = lineLayout;
-
+        oneHyphenLaidOut             = false;
         // Must break the line. Update the line layout and return.
         MergeLineLayout(lineLayout, tmpLineLayout);
 
@@ -631,7 +647,8 @@ struct Engine::Impl
       if(isMultiline &&
          (TextAbstraction::LINE_ALLOW_BREAK == lineBreakInfo))
       {
-        oneWordLaidOut = isWordLaidOut;
+        oneHyphenLaidOut = false;
+        oneWordLaidOut   = isWordLaidOut;
         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  One word laid-out\n");
 
         // Current glyph is the last one of the current word.
@@ -641,6 +658,33 @@ struct Engine::Impl
         tmpLineLayout.Clear();
       }
 
+      if(isMultiline &&
+         ((isHyphenMode || (!oneWordLaidOut && isMixedMode))) &&
+         (TextAbstraction::LINE_HYPHENATION_BREAK == lineBreakInfo))
+      {
+        hyphenGlyph        = GlyphInfo();
+        hyphenGlyph.fontId = glyphsBuffer[glyphIndex].fontId;
+
+        TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+        hyphenGlyph.index                      = fontClient.GetGlyphIndex(hyphenGlyph.fontId, HYPHEN_UNICODE);
+
+        mMetrics->GetGlyphMetrics(&hyphenGlyph, 1);
+
+        if((tmpLineLayout.length + hyphenGlyph.width) <= parameters.boundingBox.width)
+        {
+          hyphenIndex      = glyphIndex;
+          oneHyphenLaidOut = true;
+
+          DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  One hyphen laid-out\n");
+
+          // Current glyph is the last one of the current word hyphen.
+          // Add the temporal layout to the current one.
+          MergeLineLayout(lineLayout, tmpLineLayout);
+
+          tmpLineLayout.Clear();
+        }
+      }
+
       glyphIndex += numberOfGLyphsInGroup;
     }
 
@@ -1059,6 +1103,9 @@ struct Engine::Impl
     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);
 
+    layoutParameters.textModel->mVisualModel->mHyphen.glyph.Clear();
+    layoutParameters.textModel->mVisualModel->mHyphen.index.Clear();
+
     Vector<LineRun>& lines = layoutParameters.textModel->mVisualModel->mLines;
 
     if(0u == layoutParameters.numberOfGlyphs)
@@ -1271,6 +1318,17 @@ struct Engine::Impl
 
       if(ellipsis)
       {
+        //clear hyphen from ellipsis line
+        const Length* hyphenIndices = layoutParameters.textModel->mVisualModel->mHyphen.index.Begin();
+        Length        hyphensCount  = layoutParameters.textModel->mVisualModel->mHyphen.glyph.Size();
+
+        while(hyphenIndices && hyphensCount > 0 && hyphenIndices[hyphensCount - 1] >= layout.glyphIndex)
+        {
+          layoutParameters.textModel->mVisualModel->mHyphen.index.Remove(layoutParameters.textModel->mVisualModel->mHyphen.index.Begin() + hyphensCount - 1);
+          layoutParameters.textModel->mVisualModel->mHyphen.glyph.Remove(layoutParameters.textModel->mVisualModel->mHyphen.glyph.Begin() + hyphensCount - 1);
+          hyphensCount--;
+        }
+
         // No more lines to layout.
         break;
       }
index 12929fc..0de63d5 100644 (file)
@@ -296,6 +296,15 @@ void LogicalModel::UpdateTextStyleRuns(CharacterIndex index, int numberOfCharact
                                 mColorRuns,
                                 removedColorRuns);
 
+  // This is needed until now for underline tag in mark-up processor
+  // Process the underlined runs.
+  Vector<UnderlinedCharacterRun> removedUnderlinedCharacterRuns;
+  UpdateCharacterRuns<UnderlinedCharacterRun>(index,
+                                numberOfCharacters,
+                                totalNumberOfCharacters,
+                                mUnderlinedCharacterRuns,
+                                removedUnderlinedCharacterRuns);
+
   // Process the background color runs.
   Vector<ColorRun> removedBackgroundColorRuns;
   UpdateCharacterRuns<ColorRun>(index,
index 921d911..80a1285 100644 (file)
@@ -33,6 +33,7 @@
 #include <dali-toolkit/internal/text/font-run.h>
 #include <dali-toolkit/internal/text/paragraph-run.h>
 #include <dali-toolkit/internal/text/script-run.h>
+#include <dali-toolkit/internal/text/underlined-character-run.h>
 
 namespace Dali
 {
@@ -219,6 +220,7 @@ public:
   Vector<BidirectionalLineInfoRun>      mBidirectionalLineInfo;
   Vector<EmbeddedItem>                  mEmbeddedItems;
   Vector<Anchor>                        mAnchors;
+  Vector<UnderlinedCharacterRun>        mUnderlinedCharacterRuns; ///< The underlined character run from markup-processor
 
   BidirectionalLineRunIndex mBidirectionalLineIndex; ///< The last fetched bidirectional line info.
 };
index a8a6ecc..ea7f869 100644 (file)
@@ -156,6 +156,17 @@ void Initialize(ColorRun& colorRun)
 }
 
 /**
+ * @brief Initializes a underlined character run to its defaults.
+ *
+ * @param[in,out] underlinedCharacterRun The underelined character run to initialize.
+ */
+void Initialize(UnderlinedCharacterRun& underlinedCharacterRun)
+{
+  underlinedCharacterRun.characterRun.characterIndex     = 0u;
+  underlinedCharacterRun.characterRun.numberOfCharacters = 0u;
+}
+
+/**
  * @brief Splits the tag string into the tag name and its attributes.
  *
  * The attributes are stored in a vector in the tag.
@@ -498,9 +509,9 @@ bool XHTMLNumericEntityToUtf8(const char* markupText, char* utf8)
 }
 
 /**
- * @brief Processes a particular tag for the required run (color-run or font-run).
+ * @brief Processes a particular tag for the required run (color-run, font-run or underlined-character-run).
  *
- * @tparam RunType Whether ColorRun or FontDescriptionRun
+ * @tparam RunType Whether ColorRun , FontDescriptionRun or UnderlinedCharacterRun
  *
  * @param[in/out] runsContainer The container containing all the runs
  * @param[in/out] styleStack The style stack
@@ -619,11 +630,13 @@ void ProcessAnchorTag(
  * @param[in/out] markupProcessData The markup process data
  * @param[in] fontRunIndex The font run index
  * @param[in] colorRunIndex The color run index
+ * @param[in] underlinedCharacterRunIndex The underlined character run index
  */
-void ResizeModelVectors(MarkupProcessData& markupProcessData, const StyleStack::RunIndex fontRunIndex, const StyleStack::RunIndex colorRunIndex)
+void ResizeModelVectors(MarkupProcessData& markupProcessData, const StyleStack::RunIndex fontRunIndex, const StyleStack::RunIndex colorRunIndex, const StyleStack::RunIndex underlinedCharacterRunIndex)
 {
   markupProcessData.fontRuns.Resize(fontRunIndex);
   markupProcessData.colorRuns.Resize(colorRunIndex);
+  markupProcessData.underlinedCharacterRuns.Resize(underlinedCharacterRunIndex);
 
 #ifdef DEBUG_ENABLED
   for(unsigned int i = 0; i < colorRunIndex; ++i)
@@ -740,18 +753,21 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
   StyleStack styleStack;
 
   // Points the next free position in the vector of runs.
-  StyleStack::RunIndex colorRunIndex = 0u;
-  StyleStack::RunIndex fontRunIndex  = 0u;
+  StyleStack::RunIndex colorRunIndex                = 0u;
+  StyleStack::RunIndex fontRunIndex                 = 0u;
+  StyleStack::RunIndex underlinedCharacterRunIndex  = 0u;
 
   // check tag reference
   int colorTagReference = 0u;
   int fontTagReference  = 0u;
   int iTagReference     = 0u;
   int bTagReference     = 0u;
+  int uTagReference     = 0u;
 
   // Give an initial default value to the model's vectors.
   markupProcessData.colorRuns.Reserve(DEFAULT_VECTOR_SIZE);
   markupProcessData.fontRuns.Reserve(DEFAULT_VECTOR_SIZE);
+  markupProcessData.underlinedCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
 
   // Get the mark-up string buffer.
   const char*       markupStringBuffer    = markupString.c_str();
@@ -781,9 +797,9 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
       } // <i></i>
       else if(TokenComparison(XHTML_U_TAG, tag.buffer, tag.length))
       {
-        // TODO: If !tag.isEndTag, then create a new underline run.
-        //       else Pop the top of the stack and set the number of characters of the run.
-      } // <u></u>
+        ProcessTagForRun<UnderlinedCharacterRun>(
+          markupProcessData.underlinedCharacterRuns, styleStack, tag, characterIndex, underlinedCharacterRunIndex, uTagReference, [](const Tag& tag, UnderlinedCharacterRun& run) {  });
+      }  // <u></u>
       else if(TokenComparison(XHTML_B_TAG, tag.buffer, tag.length))
       {
         ProcessTagForRun<FontDescriptionRun>(
@@ -836,7 +852,7 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
   }
 
   // Resize the model's vectors.
-  ResizeModelVectors(markupProcessData, fontRunIndex, colorRunIndex);
+  ResizeModelVectors(markupProcessData, fontRunIndex, colorRunIndex, underlinedCharacterRunIndex);
 }
 
 } // namespace Text
index c75ca0c..ec45957 100644 (file)
@@ -27,6 +27,7 @@
 #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>
+#include <dali-toolkit/internal/text/underlined-character-run.h>
 
 namespace Dali
 {
@@ -42,20 +43,23 @@ struct MarkupProcessData
   MarkupProcessData(Vector<ColorRun>&           colorRuns,
                     Vector<FontDescriptionRun>& fontRuns,
                     Vector<EmbeddedItem>&       items,
-                    Vector<Anchor>&             anchors)
+                    Vector<Anchor>&             anchors,
+                    Vector<UnderlinedCharacterRun>& underlinedCharacterRuns)
   : colorRuns(colorRuns),
     fontRuns(fontRuns),
     items(items),
     anchors(anchors),
+    underlinedCharacterRuns(underlinedCharacterRuns),
     markupProcessedText()
   {
   }
 
-  Vector<ColorRun>&           colorRuns;           ///< The color runs.
-  Vector<FontDescriptionRun>& fontRuns;            ///< The font description runs.
-  Vector<EmbeddedItem>&       items;               ///< The embedded items.
-  Vector<Anchor>&             anchors;             ///< The anchors.
-  std::string                 markupProcessedText; ///< The mark-up string.
+  Vector<ColorRun>&               colorRuns;               ///< The color runs.
+  Vector<FontDescriptionRun>&     fontRuns;                ///< The font description runs.
+  Vector<EmbeddedItem>&           items;                   ///< The embedded items.
+  Vector<Anchor>&                 anchors;                 ///< The anchors.
+  Vector<UnderlinedCharacterRun>& underlinedCharacterRuns; ///< The underlined character runs.
+  std::string                     markupProcessedText;     ///< The mark-up string.
 };
 
 /**
index 208460c..1023dc4 100644 (file)
@@ -46,10 +46,6 @@ Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT
 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 uint32_t MAX_ATLAS_WIDTH  = 1024u;
-const uint32_t MAX_ATLAS_HEIGHT = 1024u;
 const uint32_t DOUBLE_PIXEL_PADDING = 4u;//Padding will be added twice to Atlas
 const uint16_t NO_OUTLINE           = 0u;
 } // namespace
@@ -85,7 +81,8 @@ struct AtlasRenderer::Impl
       mRight(0.0f),
       mUnderlinePosition(0.0f),
       mUnderlineThickness(0.0f),
-      mMeshRecordIndex(0u)
+      mMeshRecordIndex(0u),
+      mUnderlineChunkId(0u)
     {
     }
 
@@ -95,6 +92,7 @@ struct AtlasRenderer::Impl
     float    mUnderlinePosition;
     float    mUnderlineThickness;
     uint32_t mMeshRecordIndex;
+    uint32_t mUnderlineChunkId;
   };
 
   struct MaxBlockSize
@@ -175,6 +173,9 @@ struct AtlasRenderer::Impl
 
   void CacheGlyph(const GlyphInfo& glyph, FontId lastFontId, const AtlasGlyphManager::GlyphStyle& style, AtlasManager::AtlasSlot& slot)
   {
+    const Size& defaultTextAtlasSize = mFontClient.GetDefaultTextAtlasSize(); //Retrieve default size of text-atlas-block from font-client.
+    const Size& maximumTextAtlasSize = mFontClient.GetMaximumTextAtlasSize(); //Retrieve maximum size of text-atlas-block from font-client.
+
     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");
@@ -248,15 +249,15 @@ struct AtlasRenderer::Impl
           // 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.
-          uint32_t default_width = DEFAULT_ATLAS_WIDTH;
-          uint32_t default_height = DEFAULT_ATLAS_HEIGHT;
+          uint32_t default_width = defaultTextAtlasSize.width;
+          uint32_t default_height = defaultTextAtlasSize.height;
 
           while (
             (blockSize.mNeededBlockWidth >= (default_width - (DOUBLE_PIXEL_PADDING + 1u)) ||
              blockSize.mNeededBlockHeight >= (default_height - (DOUBLE_PIXEL_PADDING + 1u)))
             &&
-            (default_width < MAX_ATLAS_WIDTH &&
-             default_height < MAX_ATLAS_HEIGHT))
+            (default_width < maximumTextAtlasSize.width &&
+             default_height < maximumTextAtlasSize.height))
           {
             default_width <<= 1u;
             default_height <<= 1u;
@@ -288,7 +289,8 @@ struct AtlasRenderer::Impl
                     float                    currentUnderlineThickness,
                     std::vector<MeshRecord>& meshContainer,
                     Vector<TextCacheEntry>&  newTextCache,
-                    Vector<Extent>&          extents)
+                    Vector<Extent>&          extents,
+                    uint32_t                 underlineChunkId)
   {
     // Generate mesh data for this quad, plugging in our supplied position
     AtlasManager::Mesh2D newMesh;
@@ -324,7 +326,8 @@ struct AtlasRenderer::Impl
                    underlineGlyph,
                    currentUnderlinePosition,
                    currentUnderlineThickness,
-                   slot);
+                   slot,
+                   underlineChunkId);
   }
 
   void CreateActors(const std::vector<MeshRecord>& meshContainer,
@@ -416,16 +419,19 @@ struct AtlasRenderer::Impl
     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 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 GlyphInfo* hyphens       = view.GetHyphens();
+    const Length*    hyphenIndices = view.GetHyphenIndices();
+    const Length     hyphensCount  = view.GetHyphensCount();
 
     const bool useDefaultColor = (NULL == colorsBuffer);
 
@@ -457,12 +463,28 @@ struct AtlasRenderer::Impl
     const GlyphInfo* const glyphsBuffer    = glyphs.Begin();
     const Vector2* const   positionsBuffer = positions.Begin();
     const Vector2          lineOffsetPosition(minLineOffset, 0.f);
+    uint32_t               hyphenIndex = 0;
+
+    //For septated underlined chunks. (this is for Markup case)
+    uint32_t underlineChunkId = 0u; // give id for each chunk.
+    bool     isPreUnderlined = false; // status of underlined for previous glyph.
 
     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;
+      GlyphInfo glyph;
+      bool      addHyphen = ((hyphenIndex < hyphensCount) && hyphenIndices && (i == hyphenIndices[hyphenIndex]));
+      if(addHyphen && hyphens)
+      {
+        glyph = hyphens[hyphenIndex];
+        i--;
+      }
+      else
+      {
+        glyph = *(glyphsBuffer + i);
+      }
+
+      const bool isGlyphUnderlined = underlineEnabled || IsGlyphUnderlined(i, underlineRuns);
+      thereAreUnderlinedGlyphs     = thereAreUnderlinedGlyphs || isGlyphUnderlined;
 
       // No operation for white space
       if(glyph.width && glyph.height)
@@ -504,6 +526,7 @@ struct AtlasRenderer::Impl
           }
 
           lastUnderlinedFontId = glyph.fontId;
+
         } // underline
 
         AtlasGlyphManager::GlyphStyle style;
@@ -521,8 +544,16 @@ struct AtlasRenderer::Impl
         }
 
         // Move the origin (0,0) of the mesh to the center of the actor
-        const Vector2& temp     = *(positionsBuffer + i);
-        const Vector2  position = Vector2(roundf(temp.x), temp.y) - halfTextSize - lineOffsetPosition; // roundf() avoids pixel alignment issues.
+        Vector2 position = *(positionsBuffer + i);
+
+        if(addHyphen)
+        {
+          GlyphInfo tempInfo = *(glyphsBuffer + i);
+          position.x         = position.x + tempInfo.advance - tempInfo.xBearing + glyph.xBearing;
+          position.y += tempInfo.yBearing - glyph.yBearing;
+        }
+
+        position = Vector2(roundf(position.x), position.y) - halfTextSize - lineOffsetPosition; // roundf() avoids pixel alignment issues.
 
         if(0u != slot.mImageId) // invalid slot id, glyph has failed to be added to atlas
         {
@@ -548,7 +579,8 @@ struct AtlasRenderer::Impl
                        currentUnderlineThickness,
                        meshContainer,
                        newTextCache,
-                       extents);
+                       extents,
+                       underlineChunkId);
 
           lastFontId = glyph.fontId; // Prevents searching for existing blocksizes when string of the same fontId.
         }
@@ -565,8 +597,24 @@ struct AtlasRenderer::Impl
                        currentUnderlineThickness,
                        meshContainerOutline,
                        newTextCache,
-                       extents);
+                       extents,
+                       0u);
         }
+
+
+        //The new underlined chunk. Add new id if they are not consecutive indices (this is for Markup case)
+        // Examples: "Hello <u>World</u> Hello <u>World</u>", "<u>World</u> Hello <u>World</u>", "<u>   World</u> Hello <u>World</u>"
+        if( isPreUnderlined && (isPreUnderlined != isGlyphUnderlined))
+        {
+          underlineChunkId++;
+        }
+        //Keep status of underlined for previous glyph to check consecutive indices
+        isPreUnderlined = isGlyphUnderlined;
+      }
+
+      if(addHyphen)
+      {
+        hyphenIndex++;
       }
     } // glyphs
 
@@ -717,7 +765,8 @@ struct AtlasRenderer::Impl
                       bool                     underlineGlyph,
                       float                    underlinePosition,
                       float                    underlineThickness,
-                      AtlasManager::AtlasSlot& slot)
+                      AtlasManager::AtlasSlot& slot,
+                      uint32_t                 underlineChunkId)
   {
     if(slot.mImageId)
     {
@@ -745,7 +794,8 @@ struct AtlasRenderer::Impl
                           right,
                           baseLine,
                           underlinePosition,
-                          underlineThickness);
+                          underlineThickness,
+                          underlineChunkId);
           }
 
           return;
@@ -768,7 +818,8 @@ struct AtlasRenderer::Impl
                       right,
                       baseLine,
                       underlinePosition,
-                      underlineThickness);
+                      underlineThickness,
+                      underlineChunkId);
       }
     }
   }
@@ -780,7 +831,8 @@ struct AtlasRenderer::Impl
                      float                    right,
                      float                    baseLine,
                      float                    underlinePosition,
-                     float                    underlineThickness)
+                     float                    underlineThickness,
+                     uint32_t                 underlineChunkId)
   {
     bool foundExtent = false;
     for(Vector<Extent>::Iterator eIt    = extents.Begin(),
@@ -788,7 +840,7 @@ struct AtlasRenderer::Impl
         eIt != eEndIt;
         ++eIt)
     {
-      if(Equals(baseLine, eIt->mBaseLine))
+      if(Equals(baseLine, eIt->mBaseLine) && underlineChunkId == eIt->mUnderlineChunkId)
       {
         foundExtent = true;
         if(left < eIt->mLeft)
@@ -819,6 +871,7 @@ struct AtlasRenderer::Impl
       extent.mUnderlinePosition  = underlinePosition;
       extent.mUnderlineThickness = underlineThickness;
       extent.mMeshRecordIndex    = index;
+      extent.mUnderlineChunkId = underlineChunkId;
       extents.PushBack(extent);
     }
   }
index abf7325..83d67d5 100644 (file)
@@ -595,6 +595,10 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
       // Combine the two buffers
       imageBuffer = CombineImageBuffer(imageBuffer, backgroundImageBuffer, bufferWidth, bufferHeight);
     }
+
+    // Markup-Processor
+
+    imageBuffer = ApplyMarkupProcessorOnPixelBuffer(imageBuffer, bufferWidth, bufferHeight, ignoreHorizontalAlignment, pixelFormat, penX, penY);
   }
 
   // Create the final PixelData for the combined image buffer
@@ -613,6 +617,9 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
   const Vector2* const    positionBuffer     = mModel->GetLayout();
   const Vector4* const    colorsBuffer       = mModel->GetColors();
   const ColorIndex* const colorIndexBuffer   = mModel->GetColorIndices();
+  const GlyphInfo*        hyphens            = mModel->GetHyphens();
+  const Length*           hyphenIndices      = mModel->GetHyphenIndices();
+  const Length            hyphensCount       = mModel->GetHyphensCount();
 
   // Whether to use the default color.
   const bool     useDefaultColor = (NULL == colorsBuffer);
@@ -638,7 +645,8 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
   }
 
   // Get a handle of the font client. Used to retrieve the bitmaps of the glyphs.
-  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  TextAbstraction::FontClient fontClient  = TextAbstraction::FontClient::Get();
+  Length                      hyphenIndex = 0;
 
   // Traverses the lines of the text.
   for(LineIndex lineIndex = 0u; lineIndex < modelNumberOfLines; ++lineIndex)
@@ -703,6 +711,7 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
     float lineExtentLeft  = bufferWidth;
     float lineExtentRight = 0.0f;
     float baseline        = 0.0f;
+    bool  addHyphen       = false;
 
     // Traverses the glyphs of the line.
     const GlyphIndex endGlyphIndex = std::min(numberOfGlyphs, line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs);
@@ -715,7 +724,17 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
       }
 
       // Retrieve the glyph's info.
-      const GlyphInfo* const glyphInfo = glyphsBuffer + glyphIndex;
+      const GlyphInfo* glyphInfo;
+
+      if(addHyphen && hyphens)
+      {
+        glyphInfo = hyphens + hyphenIndex;
+        hyphenIndex++;
+      }
+      else
+      {
+        glyphInfo = glyphsBuffer + glyphIndex;
+      }
 
       if((glyphInfo->width < Math::MACHINE_EPSILON_1000) ||
          (glyphInfo->height < Math::MACHINE_EPSILON_1000))
@@ -735,21 +754,29 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
       } // underline
 
       // Retrieves the glyph's position.
-      const Vector2* const position = positionBuffer + glyphIndex;
-      if(baseline < position->y + glyphInfo->yBearing)
+      Vector2 position = *(positionBuffer + glyphIndex);
+
+      if(addHyphen)
+      {
+        GlyphInfo tempInfo = *(glyphsBuffer + glyphIndex);
+        position.x         = position.x + tempInfo.advance - tempInfo.xBearing + glyphInfo->xBearing;
+        position.y         = -glyphInfo->yBearing;
+      }
+
+      if(baseline < position.y + glyphInfo->yBearing)
       {
-        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)
+      if(position.x < lineExtentLeft)
       {
-        lineExtentLeft = position->x;
+        lineExtentLeft = position.x;
       }
 
-      if(position->x + glyphInfo->width > lineExtentRight)
+      if(position.x + glyphInfo->width > lineExtentRight)
       {
-        lineExtentRight = position->x + glyphInfo->width;
+        lineExtentRight = position.x + glyphInfo->width;
       }
 
       // Retrieves the glyph's color.
@@ -807,7 +834,7 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
 
         // Set the buffer of the glyph's bitmap into the final bitmap's buffer
         TypesetGlyph(glyphData,
-                     position,
+                     &position,
                      &color,
                      style,
                      pixelFormat);
@@ -823,6 +850,20 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
         delete[] glyphData.glyphBitmap.buffer;
         glyphData.glyphBitmap.buffer = NULL;
       }
+
+      if(hyphenIndices)
+      {
+        while((hyphenIndex < hyphensCount) && (glyphIndex > hyphenIndices[hyphenIndex]))
+        {
+          hyphenIndex++;
+        }
+
+        addHyphen = ((hyphenIndex < hyphensCount) && ((glyphIndex + 1) == hyphenIndices[hyphenIndex]));
+        if(addHyphen)
+        {
+          glyphIndex--;
+        }
+      }
     }
 
     // Draw the underline from the leftmost glyph to the rightmost glyph
@@ -906,6 +947,48 @@ Devel::PixelBuffer Typesetter::CombineImageBuffer(Devel::PixelBuffer topPixelBuf
   return combinedPixelBuffer;
 }
 
+Devel::PixelBuffer Typesetter::ApplyMarkupProcessorOnPixelBuffer(Devel::PixelBuffer topPixelBuffer, const unsigned int bufferWidth, const unsigned int bufferHeight, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int horizontalOffset, int verticalOffset)
+{
+  // Apply the markup-Processor if enabled
+  const bool markupProcessorEnabled = mModel->IsMarkupProcessorEnabled();
+  if(markupProcessorEnabled)
+  {
+    // Underline-tags (this is for Markup case)
+    // Get the underline runs.
+    const Length     numberOfUnderlineRuns = mModel->GetNumberOfUnderlineRuns();
+    Vector<GlyphRun> underlineRuns;
+    underlineRuns.Resize(numberOfUnderlineRuns);
+    mModel->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
+
+    // Iterate on the consecutive underlined glyph run and connect them into one chunk of underlined characters.
+    Vector<GlyphRun>::ConstIterator itGlyphRun    = underlineRuns.Begin();
+    Vector<GlyphRun>::ConstIterator endItGlyphRun = underlineRuns.End();
+    GlyphIndex                      startGlyphIndex, endGlyphIndex;
+
+    //The outer loop to iterate on the separated chunks of underlined glyph runs
+    while(itGlyphRun != endItGlyphRun)
+    {
+      startGlyphIndex = itGlyphRun->glyphIndex;
+      endGlyphIndex   = startGlyphIndex;
+      //The inner loop to make a connected underline for the consecutive characters
+      do
+      {
+        endGlyphIndex += itGlyphRun->numberOfGlyphs;
+        itGlyphRun++;
+      } while(itGlyphRun != endItGlyphRun && itGlyphRun->glyphIndex == endGlyphIndex);
+
+      endGlyphIndex--;
+
+      // Create the image buffer for underline
+      Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, horizontalOffset, verticalOffset, startGlyphIndex, endGlyphIndex);
+      // Combine the two buffers
+      topPixelBuffer = CombineImageBuffer(topPixelBuffer, underlineImageBuffer, bufferWidth, bufferHeight);
+    }
+  }
+
+  return topPixelBuffer;
+}
+
 Typesetter::Typesetter(const ModelInterface* const model)
 : mModel(new ViewModel(model))
 {
index 2f29a47..c9cd4cc 100644 (file)
@@ -163,6 +163,27 @@ private:
    */
   Devel::PixelBuffer CombineImageBuffer(Devel::PixelBuffer topPixelBuffer, Devel::PixelBuffer bottomPixelBuffer, const unsigned int bufferWidth, const unsigned int bufferHeightbool);
 
+  /**
+   * @brief Apply behaviour of tags if the markup-processor is enabled.
+   *
+   * The properties on TextLabel override the behavior of Markup.
+   * Because the markup will be the bottom layer buffer
+   *  - i.e: If you set property UNDERLINE to enabled and blue.
+   *    And the TEXT is "<color value='green'>Hello</color> <u>World</u> <i>Hello</i> <b>World</b>".
+   *    Then the output of the whole text is underlined by blue line.
+   *
+   * @param[in] topPixelBuffer The top layer buffer.
+   * @param[in] bufferWidth The width of the image buffer.
+   * @param[in] bufferHeight The height of the image buffer.
+   * @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.
+   *
+   * @return The image buffer with the markup.
+   */
+  Devel::PixelBuffer ApplyMarkupProcessorOnPixelBuffer(Devel::PixelBuffer topPixelBuffer, const unsigned int bufferWidth, const unsigned int bufferHeight, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int horizontalOffset, int verticalOffset);
+
 protected:
   /**
    * @brief A reference counted object may only be deleted by calling Unreference().
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
deleted file mode 100644 (file)
index 48a8335..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-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
deleted file mode 100644 (file)
index 37b1b13..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-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";
index 4be2524..6ff571a 100644 (file)
 #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>
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.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
@@ -203,14 +50,14 @@ GlyphyShader GlyphyShader::New(const Dali::Vector4& atlasInfo)
   std::ostringstream vertexShaderStringStream;
   std::ostringstream fragmentShaderStringStream;
 
-  vertexShaderStringStream << ENABLE_EXTENSION_PREFIX << VERTEX_SHADER_MAIN;
+  vertexShaderStringStream << SHADER_GLYPHY_SHADER_EXTENTION_PREFIX_DEF.data() << SHADER_GLYPHY_SHADER_MAIN_VERT.data();
 
-  fragmentShaderStringStream << ENABLE_EXTENSION_PREFIX
-                             << FRAGMENT_SHADER_PREFIX
-                             << glyphy_common_glsl
+  fragmentShaderStringStream << SHADER_GLYPHY_SHADER_EXTENTION_PREFIX_DEF.data()
+                             << SHADER_GLYPHY_SHADER_FRAGMENT_PREFIX_FRAG.data()
+                             << SHADER_GLYPHY_COMMON_GLSL_SHADER_DEF.data()
                              << "#define GLYPHY_SDF_PSEUDO_DISTANCE 1\n"
-                             << glyphy_sdf_glsl
-                             << FRAGMENT_SHADER_MAIN;
+                             << SHADER_GLYPHY_SDF_GLSL_SHADER_DEF.data()
+                             << SHADER_GLYPHY_SHADER_MAIN_FRAG.data();
 
   Shader shaderEffectCustom = Shader::New(vertexShaderStringStream.str(),
                                           fragmentShaderStringStream.str(),
index e7b40a5..f695cd2 100644 (file)
@@ -225,6 +225,26 @@ bool ViewModel::IsBackgroundEnabled() const
   return mModel->IsBackgroundEnabled();
 }
 
+bool ViewModel::IsMarkupProcessorEnabled() const
+{
+  return mModel->IsMarkupProcessorEnabled();
+}
+
+const GlyphInfo* ViewModel::GetHyphens() const
+{
+  return mModel->GetHyphens();
+}
+
+const Length* ViewModel::GetHyphenIndices() const
+{
+  return mModel->GetHyphenIndices();
+}
+
+Length ViewModel::GetHyphensCount() const
+{
+  return mModel->GetHyphensCount();
+}
+
 void ViewModel::ElideGlyphs()
 {
   mIsTextElided = false;
index a84810a..9272956 100644 (file)
@@ -211,6 +211,26 @@ public:
   bool IsBackgroundEnabled() const override;
 
   /**
+   * @copydoc ModelInterface::IsMarkupProcessorEnabled()
+   */
+  bool IsMarkupProcessorEnabled() const override;
+
+  /**
+  * @copydoc ModelInterface::GetHyphens()
+  */
+  const GlyphInfo* GetHyphens() const override;
+
+  /**
+  * @copydoc ModelInterface::GetHyphens()
+  */
+  const Length* GetHyphenIndices() const override;
+
+  /**
+  * @copydoc ModelInterface::GetHyphens()
+  */
+  Length GetHyphensCount() const override;
+
+  /**
    * @brief Does the text elide.
    *
    * It stores a copy of the visible glyphs and removes as many glyphs as needed
index 22525db..29f6ba3 100644 (file)
@@ -155,7 +155,10 @@ bool ControllerImplEventHandler::ProcessInputEvents(Controller::Impl& impl)
     eventData->mUpdateCursorPosition     = false;
     eventData->mUpdateGrabHandlePosition = false;
   }
-  else
+
+  if(eventData->mUpdateHighlightBox ||
+     eventData->mUpdateLeftSelectionPosition ||
+     eventData->mUpdateRightSelectionPosition)
   {
     CursorInfo leftHandleInfo;
     CursorInfo rightHandleInfo;
index ec00903..417eaed 100644 (file)
@@ -29,6 +29,7 @@
 #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/hyphenator.h>
 #include <dali-toolkit/internal/text/multi-language-support.h>
 #include <dali-toolkit/internal/text/segmentation.h>
 #include <dali-toolkit/internal/text/shaper.h>
@@ -37,6 +38,8 @@
 #include <dali-toolkit/internal/text/text-run-container.h>
 #include <dali-toolkit/internal/text/text-selection-handle-controller.h>
 
+#include <dali-toolkit/internal/text/text-enumerations-impl.h>
+
 using namespace Dali;
 
 namespace
@@ -587,7 +590,7 @@ bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
   Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
   Vector<Character>  displayCharacters;
   bool               useHiddenText = false;
-  if(mHiddenInput && mEventData != NULL && !mEventData->mIsShowingPlaceholderText)
+  if(mHiddenInput && mEventData != nullptr && !mEventData->mIsShowingPlaceholderText)
   {
     mHiddenInput->Substitute(srcCharacters, displayCharacters);
     useHiddenText = true;
@@ -661,6 +664,39 @@ bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
                      requestedNumberOfCharacters,
                      lineBreakInfo);
 
+    if(mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+       mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
+    {
+      CharacterIndex end                 = startIndex + requestedNumberOfCharacters;
+      LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
+
+      for(CharacterIndex index = startIndex; index < end; index++)
+      {
+        CharacterIndex wordEnd = index;
+        while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
+        {
+          wordEnd++;
+        }
+
+        if((wordEnd + 1) == end) // add last char
+        {
+          wordEnd++;
+        }
+
+        Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
+
+        for(CharacterIndex i = 0; i < (wordEnd - index); i++)
+        {
+          if(hyphens[i])
+          {
+            *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
+          }
+        }
+
+        index = wordEnd;
+      }
+    }
+
     // Create the paragraph info.
     mModel->mLogicalModel->CreateParagraphInfo(startIndex,
                                                requestedNumberOfCharacters);
@@ -697,27 +733,30 @@ bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
       TextAbstraction::FontDescription defaultFontDescription;
       TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale;
 
-      if(IsShowingPlaceholderText() && mEventData && (NULL != mEventData->mPlaceholderFont))
+      //Get the number of points per one unit of point-size
+      uint32_t numberOfPointsPerOneUnitOfPointSize = mFontClient.GetNumberOfPointsPerOneUnitOfPointSize();
+
+      if(IsShowingPlaceholderText() && mEventData && (nullptr != 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 * mFontSizeScale * 64u;
+          defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * mFontSizeScale * numberOfPointsPerOneUnitOfPointSize;
         }
       }
-      else if(NULL != mFontDefaults)
+      else if(nullptr != mFontDefaults)
       {
         // Set the normal font and the placeholder font.
         defaultFontDescription = mFontDefaults->mFontDescription;
 
         if(mTextFitEnabled)
         {
-          defaultPointSize = mFontDefaults->mFitPointSize * 64u;
+          defaultPointSize = mFontDefaults->mFitPointSize * numberOfPointsPerOneUnitOfPointSize;
         }
         else
         {
-          defaultPointSize = mFontDefaults->mDefaultPointSize * mFontSizeScale * 64u;
+          defaultPointSize = mFontDefaults->mDefaultPointSize * mFontSizeScale * numberOfPointsPerOneUnitOfPointSize;
         }
       }
 
@@ -807,7 +846,8 @@ bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
     // 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;
+
+   updated = true;
   }
 
   const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
@@ -830,7 +870,7 @@ bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
     updated = true;
   }
 
-  if((NULL != mEventData) &&
+  if((nullptr != mEventData) &&
      mEventData->mPreEditFlag &&
      (0u != mModel->mVisualModel->mCharactersToGlyph.Count()))
   {
@@ -858,6 +898,12 @@ bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
           underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
           underlineRun.numberOfGlyphs = numberOfIndices;
           mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+          //Mark-up processor case
+          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+          {
+            CopyUnderlinedFromLogicalToVisualModels(false);
+          }
           break;
         }
         case Dali::InputMethodContext::PreeditStyle::REVERSE:
@@ -902,6 +948,12 @@ bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
           underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
           underlineRun.numberOfGlyphs = numberOfIndices;
           mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+          //Mark-up processor case
+          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+          {
+            CopyUnderlinedFromLogicalToVisualModels(false);
+          }
           break;
         }
         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
@@ -917,6 +969,12 @@ bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
           underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
           underlineRun.numberOfGlyphs = numberOfIndices;
           mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+          //Mark-up processor case
+          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+          {
+            CopyUnderlinedFromLogicalToVisualModels(false);
+          }
           break;
         }
         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
@@ -932,6 +990,12 @@ bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
           underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
           underlineRun.numberOfGlyphs = numberOfIndices;
           mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+          //Mark-up processor case
+          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+          {
+            CopyUnderlinedFromLogicalToVisualModels(false);
+          }
           break;
         }
         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
@@ -947,6 +1011,12 @@ bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
           underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
           underlineRun.numberOfGlyphs = numberOfIndices;
           mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+          //Mark-up processor case
+          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+          {
+            CopyUnderlinedFromLogicalToVisualModels(false);
+          }
           break;
         }
         case Dali::InputMethodContext::PreeditStyle::NONE:
@@ -985,6 +1055,21 @@ bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
     updated = true;
   }
 
+  if((NO_OPERATION != (SHAPE_TEXT & operations)) &&
+      ! ((nullptr != mEventData) &&
+         mEventData->mPreEditFlag &&
+         (0u != mModel->mVisualModel->mCharactersToGlyph.Count())))
+  {
+    //Mark-up processor case
+    if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+    {
+      CopyUnderlinedFromLogicalToVisualModels(true);
+    }
+
+    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());
 
@@ -1064,7 +1149,7 @@ void Controller::Impl::RetrieveDefaultInputStyle(InputStyle& inputStyle)
 float Controller::Impl::GetDefaultFontLineHeight()
 {
   FontId defaultFontId = 0u;
-  if(NULL == mFontDefaults)
+  if(nullptr == mFontDefaults)
   {
     TextAbstraction::FontDescription fontDescription;
     defaultFontId = mFontClient.GetFontId(fontDescription, TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale);
@@ -1384,7 +1469,7 @@ void Controller::Impl::SetPopupButtons()
 
 void Controller::Impl::ChangeState(EventData::State newState)
 {
-  if(NULL == mEventData)
+  if(nullptr == mEventData)
   {
     // Nothing to do if there is no text input.
     return;
@@ -1700,7 +1785,7 @@ void Controller::Impl::GetCursorPosition(CharacterIndex logical,
 
 CharacterIndex Controller::Impl::CalculateNewCursorIndex(CharacterIndex index) const
 {
-  if(NULL == mEventData)
+  if(nullptr == mEventData)
   {
     // Nothing to do if there is no text input.
     return 0u;
@@ -1750,7 +1835,7 @@ CharacterIndex Controller::Impl::CalculateNewCursorIndex(CharacterIndex index) c
 void Controller::Impl::UpdateCursorPosition(const CursorInfo& cursorInfo)
 {
   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this);
-  if(NULL == mEventData)
+  if(nullptr == mEventData)
   {
     // Nothing to do if there is no text input.
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n");
@@ -1925,7 +2010,7 @@ void Controller::Impl::ScrollTextToMatchCursor()
 
 void Controller::Impl::RequestRelayout()
 {
-  if(NULL != mControlInterface)
+  if(nullptr != mControlInterface)
   {
     mControlInterface->RequestTextRelayout();
   }
@@ -2095,6 +2180,32 @@ Actor Controller::Impl::CreateBackgroundActor()
   return actor;
 }
 
+void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns)
+{
+    //Underlined character runs for markup-processor
+    const Vector<UnderlinedCharacterRun>& underlinedCharacterRuns = mModel->mLogicalModel->mUnderlinedCharacterRuns;
+    const Vector<GlyphIndex>&             charactersToGlyph       = mModel->mVisualModel->mCharactersToGlyph;
+    const Vector<Length>&                 glyphsPerCharacter      = mModel->mVisualModel->mGlyphsPerCharacter;
+
+    if(shouldClearPreUnderlineRuns)
+    {
+        mModel->mVisualModel->mUnderlineRuns.Clear();
+    }
+
+    for(Vector<UnderlinedCharacterRun>::ConstIterator it = underlinedCharacterRuns.Begin(), endIt = underlinedCharacterRuns.End(); it != endIt; ++it)
+    {
+        CharacterIndex characterIndex = it->characterRun.characterIndex;
+        Length numberOfCharacters = it->characterRun.numberOfCharacters;
+        for(Length index=0u; index<numberOfCharacters; index++)
+        {
+          GlyphRun underlineGlyphRun;
+          underlineGlyphRun.glyphIndex     = charactersToGlyph[characterIndex + index];
+          underlineGlyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex + index];
+          mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
+        }
+    }
+}
+
 } // namespace Text
 
 } // namespace Toolkit
index ef4bb69..9f637d3 100644 (file)
@@ -785,6 +785,13 @@ private:
   // Declared private and left undefined to avoid copies.
   Impl& operator=(const Impl&);
 
+  /**
+   * @brief Copy Underlined-Character-Runs from Logical-Model to Underlined-Glyph-Runs in Visual-Model
+   *
+   * @param shouldClearPreUnderlineRuns Whether should clear the existing Underlined-Glyph-Runs in Visual-Model
+   */
+  void CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns);
+
 public:
   ControlInterface*           mControlInterface;           ///< Reference to the text controller.
   EditableControlInterface*   mEditableControlInterface;   ///< Reference to the editable text controller.
index 78e7331..134a327 100644 (file)
@@ -291,7 +291,10 @@ float Controller::Relayouter::GetHeightForWidth(Controller& controller, float wi
     // The implementation of Get LineCount property depends on calling GetHeightForWidth then read mLines.Count() from visualModel direct.
     // If the LineCount property is requested before rendering and layouting then the value will be zero, which is incorrect.
     // So we will not restore the previously backed-up mLines and mGlyphPositions from visualModel in such case.
-    bool restoreLinesAndGlyphPositions = visualModel->mControlSize.width>0 && visualModel->mControlSize.height>0;
+    // Another case to skip restore is when the requested width equals the Control's width which means the caller need to update the old values.
+    // For example, when the text is changed.
+    bool restoreLinesAndGlyphPositions = (visualModel->mControlSize.width>0 && visualModel->mControlSize.height>0)
+                                          && (visualModel->mControlSize.width != width);
 
     layoutSize = CalculateLayoutSizeOnRequiredControllerSize(controller, sizeRequestedWidthAndMaxHeight, requestedOperationsMask, restoreLinesAndGlyphPositions);
 
index 81adb8a..36a2133 100644 (file)
@@ -82,7 +82,8 @@ void Controller::TextUpdater::SetText(Controller& controller, const std::string&
     MarkupProcessData markupProcessData(logicalModel->mColorRuns,
                                         logicalModel->mFontDescriptionRuns,
                                         logicalModel->mEmbeddedItems,
-                                        logicalModel->mAnchors);
+                                        logicalModel->mAnchors,
+                                        logicalModel->mUnderlinedCharacterRuns);
 
     Length         textSize = 0u;
     const uint8_t* utf8     = NULL;
index 15db50b..6866ff4 100644 (file)
@@ -25,6 +25,7 @@
 #include <limits>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
 #include <dali-toolkit/internal/text/text-controller-event-handler.h>
 #include <dali-toolkit/internal/text/text-controller-impl.h>
 #include <dali-toolkit/internal/text/text-controller-input-font-handler.h>
@@ -124,6 +125,8 @@ void Controller::SetMarkupProcessorEnabled(bool enable)
     GetText(text);
     SetText(text);
   }
+
+  mImpl->mModel->mVisualModel->SetMarkupProcessorEnabled(enable);
 }
 
 bool Controller::IsMarkupProcessorEnabled() const
@@ -403,15 +406,22 @@ 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 |
+    mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
                                                             ALIGN |
                                                             LAYOUT |
                                                             UPDATE_LAYOUT_SIZE |
                                                             REORDER);
+
+    if((mImpl->mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+       (mImpl->mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED)) // hyphen is treated as line break
+    {
+      mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | GET_LINE_BREAKS);
+    }
+
+    // Set the text wrap mode.
+    mImpl->mModel->mLineWrapMode = lineWrapMode;
+
     mImpl->mTextUpdateInfo.mCharacterIndex             = 0u;
     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = mImpl->mModel->mLogicalModel->mText.Count();
index aafd430..c116f8f 100644 (file)
@@ -265,6 +265,34 @@ public:
    * @return The background state.
    */
   virtual bool IsBackgroundEnabled() const = 0;
+
+  /**
+   * @brief Returns whether markup-processor is enabled or not.
+   *
+   * @return The markup-processor state.
+   */
+  virtual bool IsMarkupProcessorEnabled() const = 0;
+
+  /**
+   * @brief Returns the hyphens glyph info.
+   *
+   * @return hyphens glyph info.
+   */
+  virtual const GlyphInfo* GetHyphens() const = 0;
+
+  /**
+   * @brief Returns the indices of the hyphen in the text.
+   *
+   * @return the hyphen indices.
+   */
+  virtual const Length* GetHyphenIndices() const = 0;
+
+  /**
+   * @brief Returns number of hyphens to add in text.
+   *
+   * @return number of hyphens.
+   */
+  virtual Length GetHyphensCount() const = 0;
 };
 
 } // namespace Text
index 2d60854..948044e 100644 (file)
@@ -184,6 +184,26 @@ bool Model::IsBackgroundEnabled() const
   return mVisualModel->IsBackgroundEnabled();
 }
 
+bool Model::IsMarkupProcessorEnabled() const
+{
+  return mVisualModel->IsMarkupProcessorEnabled();
+}
+
+const GlyphInfo* Model::GetHyphens() const
+{
+  return mVisualModel->mHyphen.glyph.Begin();
+}
+
+const Length* Model::GetHyphenIndices() const
+{
+  return mVisualModel->mHyphen.index.Begin();
+}
+
+Length Model::GetHyphensCount() const
+{
+  return mVisualModel->mHyphen.glyph.Size();
+}
+
 Model::Model()
 : mLogicalModel(),
   mVisualModel(),
index d52809c..4faa1bc 100644 (file)
@@ -207,6 +207,26 @@ public:
    */
   bool IsBackgroundEnabled() const override;
 
+  /**
+   * @copydoc ModelInterface::IsMarkupProcessorEnabled()
+   */
+  bool IsMarkupProcessorEnabled() const override;
+
+  /**
+  * @copydoc ModelInterface::GetHyphens()
+  */
+  const GlyphInfo* GetHyphens() const override;
+
+  /**
+  * @copydoc ModelInterface::GetHyphens()
+  */
+  const Length* GetHyphenIndices() const override;
+
+  /**
+  * @copydoc ModelInterface::GetHyphens()
+  */
+  Length GetHyphensCount() const override;
+
 private: // Private contructors & copy operator.
   /**
    * @brief Private constructor.
index 1a04135..63f7fd4 100644 (file)
@@ -159,6 +159,26 @@ public:
   virtual bool IsUnderlineEnabled() const = 0;
 
   /**
+   * @brief Returns the hyphens glyph info.
+   *
+   * @return hyphens glyph info.
+   */
+  virtual const GlyphInfo* GetHyphens() const = 0;
+
+  /**
+   * @brief Returns the indices of the hyphen in the text.
+   *
+   * @return the hyphen indices.
+   */
+  virtual const Length* GetHyphenIndices() const = 0;
+
+  /**
+   * @brief Returns number of hyphens to add in text.
+   *
+   * @return number of hyphens.
+   */
+  virtual Length GetHyphensCount() const = 0;
+  /**
    * @brief Retrieves the underline height override
    *
    * @return Returns the override height for an underline, 0 indicates that adaptor will determine the height
index 83ad28f..2f74699 100644 (file)
@@ -388,6 +388,35 @@ bool View::IsUnderlineEnabled() const
   return false;
 }
 
+const GlyphInfo* View::GetHyphens() const
+{
+  if(mImpl->mVisualModel)
+  {
+    return mImpl->mVisualModel->mHyphen.glyph.Begin();
+  }
+
+  return nullptr;
+}
+
+const Length* View::GetHyphenIndices() const
+{
+  if(mImpl->mVisualModel)
+  {
+    return mImpl->mVisualModel->mHyphen.index.Begin();
+  }
+
+  return nullptr;
+}
+
+Length View::GetHyphensCount() const
+{
+  if(mImpl->mVisualModel)
+  {
+    return mImpl->mVisualModel->mHyphen.glyph.Size();
+  }
+
+  return 0;
+}
 float View::GetUnderlineHeight() const
 {
   if(mImpl->mVisualModel)
index cc82820..3790fd0 100644 (file)
@@ -121,6 +121,21 @@ public:
   bool IsUnderlineEnabled() const override;
 
   /**
+  * @copydoc Dali::Toolkit::Text::ViewInterface::GetHyphens()
+  */
+  const GlyphInfo* GetHyphens() const override;
+
+  /**
+  * @copydoc Dali::Toolkit::Text::ViewInterface::GetHyphens()
+  */
+  const Length* GetHyphenIndices() const override;
+
+  /**
+  * @copydoc Dali::Toolkit::Text::ViewInterface::GetHyphens()
+  */
+  Length GetHyphensCount() const override;
+
+  /**
    * @copydoc Dali::Toolkit::Text::ViewInterface::GetUnderlineHeight()
    */
   float GetUnderlineHeight() const override;
diff --git a/dali-toolkit/internal/text/underlined-character-run.h b/dali-toolkit/internal/text/underlined-character-run.h
new file mode 100644 (file)
index 0000000..99d5967
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef DALI_TOOLKIT_TEXT_UNDERLINED_CHARACTER_RUN_H
+#define DALI_TOOLKIT_TEXT_UNDERLINED_CHARACTER_RUN_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 underlined characters with same properties.
+ */
+struct UnderlinedCharacterRun
+{
+  CharacterRun characterRun; ///< The initial character index and the number of characters of the run.
+  //TODO: add properties like color, height and style
+  //Vector4      color;       ///< The color of underline.
+  //float        height;      ///< The height of underline.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_UNDERLINED_CHARACTER_RUN_H
index eda5633..7edb428 100644 (file)
@@ -384,6 +384,11 @@ void VisualModel::SetBackgroundEnabled(bool enabled)
   mBackgroundEnabled = enabled;
 }
 
+void VisualModel::SetMarkupProcessorEnabled(bool enabled)
+{
+  mMarkupProcessorEnabled = enabled;
+}
+
 const Vector4& VisualModel::GetTextColor() const
 {
   return mTextColor;
@@ -439,6 +444,11 @@ bool VisualModel::IsBackgroundEnabled() const
   return mBackgroundEnabled;
 }
 
+bool VisualModel::IsMarkupProcessorEnabled() const
+{
+  return mMarkupProcessorEnabled;
+}
+
 Length VisualModel::GetNumberOfUnderlineRuns() const
 {
   return mUnderlineRuns.Count();
@@ -476,7 +486,8 @@ VisualModel::VisualModel()
   mCachedLineIndex(0u),
   mUnderlineEnabled(false),
   mUnderlineColorSet(false),
-  mBackgroundEnabled(false)
+  mBackgroundEnabled(false),
+  mMarkupProcessorEnabled(false)
 {
 }
 
index 371b666..c355c3c 100644 (file)
@@ -35,6 +35,13 @@ namespace Toolkit
 {
 namespace Text
 {
+struct HyphenInfo
+{
+  Vector<GlyphInfo> glyph;
+  Vector<Vector2>   position;
+  Vector<Length>    index;
+};
+
 class VisualModel;
 typedef IntrusivePtr<VisualModel> VisualModelPtr;
 
@@ -353,6 +360,20 @@ public:
    */
   bool IsBackgroundEnabled() const;
 
+  /**
+   * @brief Sets whether the text has a markup-processor or not.
+   *
+   * @param[in] enabled true if the text has a markup-processor.
+   */
+  void SetMarkupProcessorEnabled(bool enabled);
+
+  /**
+   * @brief Returns whether the text has a markup-processor or not.
+   *
+   * @return whether the text has a markup-processor or not.
+   */
+  bool IsMarkupProcessorEnabled() const;
+
 protected:
   /**
    * @brief A reference counted object may only be deleted by calling Unreference().
@@ -407,6 +428,8 @@ public:
   bool mUnderlineEnabled : 1;  ///< Underline enabled flag
   bool mUnderlineColorSet : 1; ///< Has the underline color been explicitly set?
   bool mBackgroundEnabled : 1; ///< Background enabled flag
+  bool mMarkupProcessorEnabled : 1; ///< Markup-processor enabled flag
+  HyphenInfo mHyphen; ///< Contains hyphen glyph info & the character index to draw hyphen after.
 };
 
 } // namespace Text
index c9623a6..30a0dfe 100644 (file)
@@ -539,7 +539,13 @@ void AnimatedImageVisual::OnInitialize()
 {
   bool   defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
   bool   atlasing        = false;
-  Shader shader          = mImageVisualShaderFactory.GetShader(mFactoryCache, atlasing, defaultWrapMode, IsRoundedCornerRequired());
+  Shader shader          = mImageVisualShaderFactory.GetShader(
+    mFactoryCache,
+    atlasing ? TextureAtlas::ENABLED : TextureAtlas::DISABLED,
+    defaultWrapMode ? DefaultTextureWrapMode::APPLY : DefaultTextureWrapMode::DO_NOT_APPLY,
+    IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
+    IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED
+  );
 
   Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
 
index c6604ad..edd7b1b 100644 (file)
@@ -295,7 +295,13 @@ void AnimatedVectorImageVisual::OnInitialize(void)
   }
   else
   {
-    shader = mImageVisualShaderFactory.GetShader(mFactoryCache, false, true, IsRoundedCornerRequired());
+    shader = mImageVisualShaderFactory.GetShader(
+      mFactoryCache,
+      TextureAtlas::DISABLED,
+      DefaultTextureWrapMode::APPLY,
+      IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
+      IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED
+    );
   }
 
   Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
index d9d6d5a..3966d0c 100644 (file)
@@ -37,7 +37,7 @@ namespace Internal
 namespace
 {
 constexpr auto LOOP_FOREVER = -1;
-constexpr auto NANOSECONDS_PER_SECOND(1e+9);
+constexpr auto MICROSECONDS_PER_SECOND(1e+6);
 
 #if defined(DEBUG_ENABLED)
 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_ANIMATION");
@@ -56,12 +56,13 @@ VectorAnimationTask::VectorAnimationTask(VisualFactoryCache& factoryCache)
   mStopBehavior(DevelImageVisual::StopBehavior::CURRENT_FRAME),
   mLoopingMode(DevelImageVisual::LoopingMode::RESTART),
   mNextFrameStartTime(),
-  mFrameDurationNanoSeconds(0),
+  mFrameDurationMicroSeconds(MICROSECONDS_PER_SECOND / 60.0f),
   mFrameRate(60.0f),
   mCurrentFrame(0),
   mTotalFrame(0),
   mStartFrame(0),
   mEndFrame(0),
+  mDroppedFrames(0),
   mWidth(0),
   mHeight(0),
   mAnimationDataIndex(0),
@@ -109,8 +110,8 @@ bool VectorAnimationTask::Load(const std::string& url)
 
   mEndFrame = mTotalFrame - 1;
 
-  mFrameRate                = mVectorRenderer.GetFrameRate();
-  mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate;
+  mFrameRate                 = mVectorRenderer.GetFrameRate();
+  mFrameDurationMicroSeconds = MICROSECONDS_PER_SECOND / mFrameRate;
 
   uint32_t width, height;
   mVectorRenderer.GetDefaultSize(width, height);
@@ -387,7 +388,7 @@ bool VectorAnimationTask::Rasterize()
 
   if(mPlayState == PlayState::PLAYING && mUpdateFrameNumber)
   {
-    mCurrentFrame = mForward ? mCurrentFrame + 1 : mCurrentFrame - 1;
+    mCurrentFrame = mForward ? mCurrentFrame + mDroppedFrames + 1 : mCurrentFrame - mDroppedFrames - 1;
     Dali::ClampInPlace(mCurrentFrame, mStartFrame, mEndFrame);
   }
 
@@ -521,22 +522,36 @@ uint32_t VectorAnimationTask::GetStoppedFrame(uint32_t startFrame, uint32_t endF
   return frame;
 }
 
-std::chrono::time_point<std::chrono::system_clock> VectorAnimationTask::CalculateNextFrameTime(bool renderNow)
+VectorAnimationTask::TimePoint 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 = std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds));
+  auto current        = std::chrono::system_clock::now();
+  if(renderNow)
   {
     mNextFrameStartTime = current;
+    mDroppedFrames      = 0;
   }
+  else if(mNextFrameStartTime < current)
+  {
+    uint32_t droppedFrames = 0;
+
+    while(current > std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds)))
+    {
+      droppedFrames++;
+      mNextFrameStartTime = std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds));
+    }
+
+    mNextFrameStartTime = current;
+    mDroppedFrames      = droppedFrames;
+  }
+
   return mNextFrameStartTime;
 }
 
-std::chrono::time_point<std::chrono::system_clock> VectorAnimationTask::GetNextFrameTime()
+VectorAnimationTask::TimePoint VectorAnimationTask::GetNextFrameTime()
 {
   return mNextFrameStartTime;
 }
index 03b8a89..c14cc10 100644 (file)
@@ -47,6 +47,8 @@ class VectorAnimationTask : public RefObject
 public:
   using UploadCompletedSignalType = Dali::VectorAnimationRenderer::UploadCompletedSignalType;
 
+  using TimePoint = std::chrono::time_point<std::chrono::system_clock>;
+
   /**
    * Flags for re-sending data to the vector animation thread
    */
@@ -195,13 +197,13 @@ public:
    * @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);
+  TimePoint 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();
+  TimePoint GetNextFrameTime();
 
 private:
   /**
@@ -284,32 +286,33 @@ private:
     PAUSED    ///< The animation is paused
   };
 
-  std::string                                        mUrl;
-  VectorAnimationRenderer                            mVectorRenderer;
-  AnimationData                                      mAnimationData[2];
-  VectorAnimationThread&                             mVectorAnimationThread;
-  ConditionalWait                                    mConditionalWait;
-  std::unique_ptr<EventThreadCallback>               mAnimationFinishedTrigger;
-  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;
-  uint32_t                                           mAnimationDataIndex;
-  int32_t                                            mLoopCount;
-  int32_t                                            mCurrentLoop;
-  bool                                               mForward;
-  bool                                               mUpdateFrameNumber;
-  bool                                               mNeedAnimationFinishedTrigger;
-  bool                                               mAnimationDataUpdated;
-  bool                                               mDestroyTask;
+  std::string                          mUrl;
+  VectorAnimationRenderer              mVectorRenderer;
+  AnimationData                        mAnimationData[2];
+  VectorAnimationThread&               mVectorAnimationThread;
+  ConditionalWait                      mConditionalWait;
+  std::unique_ptr<EventThreadCallback> mAnimationFinishedTrigger;
+  PlayState                            mPlayState;
+  DevelImageVisual::StopBehavior::Type mStopBehavior;
+  DevelImageVisual::LoopingMode::Type  mLoopingMode;
+  TimePoint                            mNextFrameStartTime;
+  int64_t                              mFrameDurationMicroSeconds;
+  float                                mFrameRate;
+  uint32_t                             mCurrentFrame;
+  uint32_t                             mTotalFrame;
+  uint32_t                             mStartFrame;
+  uint32_t                             mEndFrame;
+  uint32_t                             mDroppedFrames;
+  uint32_t                             mWidth;
+  uint32_t                             mHeight;
+  uint32_t                             mAnimationDataIndex;
+  int32_t                              mLoopCount;
+  int32_t                              mCurrentLoop;
+  bool                                 mForward;
+  bool                                 mUpdateFrameNumber;
+  bool                                 mNeedAnimationFinishedTrigger;
+  bool                                 mAnimationDataUpdated;
+  bool                                 mDestroyTask;
 };
 
 } // namespace Internal
index 9ce3a29..8f748cf 100644 (file)
@@ -39,6 +39,27 @@ namespace Toolkit
 {
 namespace Internal
 {
+namespace
+{
+VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[6] =
+{
+  VisualFactoryCache::COLOR_SHADER,
+  VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER,
+  VisualFactoryCache::COLOR_SHADER_BORDERLINE,
+  VisualFactoryCache::COLOR_SHADER_ROUNDED_BORDERLINE,
+  VisualFactoryCache::COLOR_SHADER_BLUR_EDGE,
+  VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER_BLUR_EDGE,
+};
+
+// enum of required list when we select shader
+enum ColorVisualRequireFlag
+{
+  DEFAULT        = 0,
+  ROUNDED_CORNER = 1 << 0,
+  BORDERLINE     = 1 << 1,
+  BLUR           = 1 << 2,
+};
+} // unnamed namespace
 ColorVisualPtr ColorVisual::New(VisualFactoryCache& factoryCache, const Property::Map& properties)
 {
   ColorVisualPtr colorVisualPtr(new ColorVisual(factoryCache));
@@ -51,7 +72,6 @@ ColorVisual::ColorVisual(VisualFactoryCache& factoryCache)
 : Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::COLOR),
   mBlurRadius(0.0f),
   mBlurRadiusIndex(Property::INVALID_INDEX),
-  mRenderIfTransparent(false),
   mNeedBlurRadius(false)
 {
 }
@@ -87,15 +107,6 @@ void ColorVisual::DoSetProperties(const Property::Map& propertyMap)
     }
   }
 
-  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)
   {
@@ -108,12 +119,7 @@ void ColorVisual::DoSetProperties(const Property::Map& propertyMap)
 
 void ColorVisual::DoSetOnScene(Actor& actor)
 {
-  // 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);
-  }
+  actor.AddRenderer(mImpl->mRenderer);
 
   // Color Visual generated and ready to display
   ResourceReady(Toolkit::Visual::ResourceStatus::READY);
@@ -129,7 +135,6 @@ 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);
 
   if(mImpl->mRenderer && mBlurRadiusIndex != Property::INVALID_INDEX)
   {
@@ -208,32 +213,52 @@ void ColorVisual::OnInitialize()
 Shader ColorVisual::GetShader()
 {
   Shader shader;
-  if(!EqualsZero(mBlurRadius) || mNeedBlurRadius)
+  VisualFactoryCache::ShaderType shaderType;
+
+  bool roundedCorner = IsRoundedCornerRequired();
+  bool borderline    = IsBorderlineRequired();
+  bool blur          = !EqualsZero(mBlurRadius) || mNeedBlurRadius;
+  int shaderTypeFlag = ColorVisualRequireFlag::DEFAULT;
+
+  if(roundedCorner)
   {
-    shader = mFactoryCache.GetShader(VisualFactoryCache::COLOR_SHADER_BLUR_EDGE);
-    if(!shader)
-    {
-      shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_COLOR_VISUAL_BLUR_EDGE_SHADER_VERT.data(), Dali::Shader::GetFragmentShaderPrefix() + SHADER_COLOR_VISUAL_BLUR_EDGE_SHADER_FRAG.data());
-      mFactoryCache.SaveShader(VisualFactoryCache::COLOR_SHADER_BLUR_EDGE, shader);
-    }
+    shaderTypeFlag |= ColorVisualRequireFlag::ROUNDED_CORNER;
   }
-  else if(!IsRoundedCornerRequired())
+  if(blur)
   {
-    shader = mFactoryCache.GetShader(VisualFactoryCache::COLOR_SHADER);
-    if(!shader)
-    {
-      shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_COLOR_VISUAL_SHADER_VERT.data(), Dali::Shader::GetFragmentShaderPrefix() + SHADER_COLOR_VISUAL_SHADER_FRAG.data());
-      mFactoryCache.SaveShader(VisualFactoryCache::COLOR_SHADER, shader);
-    }
+    // If we use blur, just ignore borderline
+    borderline = false;
+    shaderTypeFlag |= ColorVisualRequireFlag::BLUR;
   }
-  else
+  if(borderline)
+  {
+    shaderTypeFlag |= ColorVisualRequireFlag::BORDERLINE;
+  }
+
+  shaderType = SHADER_TYPE_TABLE[shaderTypeFlag];
+  shader = mFactoryCache.GetShader(shaderType);
+  if(!shader)
   {
-    shader = mFactoryCache.GetShader(VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER);
-    if(!shader)
+    std::string vertexShaderPrefixList;
+    std::string fragmentShaderPrefixList;
+    if(roundedCorner)
+    {
+      vertexShaderPrefixList   += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+      fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+    }
+    if(blur)
+    {
+      vertexShaderPrefixList   += "#define IS_REQUIRED_BLUR 1\n";
+      fragmentShaderPrefixList += "#define IS_REQUIRED_BLUR 1\n";
+    }
+    if(borderline)
     {
-      shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_COLOR_VISUAL_ROUNDED_CORNER_SHADER_VERT.data(), Dali::Shader::GetFragmentShaderPrefix() + SHADER_COLOR_VISUAL_ROUNDED_CORNER_SHADER_FRAG.data());
-      mFactoryCache.SaveShader(VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER, shader);
+      vertexShaderPrefixList   += "#define IS_REQUIRED_BORDERLINE 1\n";
+      fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
     }
+    shader = Shader::New(Dali::Shader::GetVertexShaderPrefix()   + vertexShaderPrefixList   + SHADER_COLOR_VISUAL_SHADER_VERT.data(),
+                         Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_COLOR_VISUAL_SHADER_FRAG.data());
+    mFactoryCache.SaveShader(shaderType, shader);
   }
 
   return shader;
index ba9a590..6fe1f43 100644 (file)
@@ -133,10 +133,9 @@ private:
   ColorVisual& operator=(const ColorVisual& colorRenderer);
 
 private:
-  float           mBlurRadius;          ///< The blur radius
-  Property::Index mBlurRadiusIndex;     ///< The blur radius property index
-  bool            mRenderIfTransparent; ///< Whether we should render even if the mix-color is transparent.
-  bool            mNeedBlurRadius;      ///< Whether we need the blur radius in shader.
+  float           mBlurRadius;      ///< The blur radius
+  Property::Index mBlurRadiusIndex; ///< The blur radius property index
+  bool            mNeedBlurRadius;  ///< Whether we need the blur radius in shader.
 };
 
 } // namespace Internal
index b122359..896b095 100644 (file)
 #include <typeinfo>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-bounding-box-rounded-corner-shader-vert.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-bounding-box-shader-vert.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-linear-rounded-corner-shader-frag.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-linear-shader-frag.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-radial-rounded-corner-shader-frag.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-radial-shader-frag.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-user-space-rounded-corner-shader-vert.h>
-#include <dali-toolkit/internal/graphics/generated/gradient-visual-user-space-shader-vert.h>
+#include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.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>
@@ -71,44 +64,35 @@ const char* const UNIFORM_ALIGNMENT_MATRIX_NAME("uAlignmentMatrix");
 const unsigned int DEFAULT_OFFSET_MINIMUM = 0.0f;
 const unsigned int DEFAULT_OFFSET_MAXIMUM = 1.0f;
 
-VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[][4] =
-  {
-    {VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE,
-     VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX,
-     VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_CORNER,
-     VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_CORNER},
-    {VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE,
-     VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
-     VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_CORNER,
-     VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_CORNER}};
-
-const std::string_view VERTEX_SHADER[] =
-  {
-    // vertex shader for gradient units as OBJECT_BOUNDING_BOX
-    SHADER_GRADIENT_VISUAL_BOUNDING_BOX_SHADER_VERT,
-
-    // vertex shader for gradient units as USER_SPACE
-    SHADER_GRADIENT_VISUAL_USER_SPACE_SHADER_VERT,
-
-    // vertex shader for gradient units as OBJECT_BOUNDING_BOX with corner radius
-    SHADER_GRADIENT_VISUAL_BOUNDING_BOX_ROUNDED_CORNER_SHADER_VERT,
-
-    // vertex shader for gradient units as USER_SPACE with corner radius
-    SHADER_GRADIENT_VISUAL_USER_SPACE_ROUNDED_CORNER_SHADER_VERT};
-
-const std::string_view FRAGMENT_SHADER[] =
-  {
-    // fragment shader for linear gradient
-    SHADER_GRADIENT_VISUAL_LINEAR_SHADER_FRAG,
-
-    // fragment shader for radial gradient
-    SHADER_GRADIENT_VISUAL_RADIAL_SHADER_FRAG,
-
-    // fragment shader for linear gradient with corner radius
-    SHADER_GRADIENT_VISUAL_LINEAR_ROUNDED_CORNER_SHADER_FRAG,
-
-    // fragment shader for radial gradient with corner radius
-    SHADER_GRADIENT_VISUAL_RADIAL_ROUNDED_CORNER_SHADER_FRAG};
+VisualFactoryCache::ShaderType SHADER_TYPE_TABLE[16] =
+{
+  VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX,
+  VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_CORNER,
+  VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_BORDERLINE,
+  VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_BORDERLINE,
+  VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE,
+  VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_CORNER,
+  VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_BORDERLINE,
+  VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_BORDERLINE,
+  VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
+  VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_CORNER,
+  VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_BORDERLINE,
+  VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_BORDERLINE,
+  VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE,
+  VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_CORNER,
+  VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_BORDERLINE,
+  VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_BORDERLINE,
+};
+
+// enum of required list when we select shader
+enum GradientVisualRequireFlag
+{
+  DEFAULT        = 0,
+  ROUNDED_CORNER = 1 << 0,
+  BORDERLINE     = 1 << 1,
+  USER_SPACE     = 1 << 2,
+  RADIAL         = 1 << 3,
+};
 
 Dali::WrapMode::Type GetWrapMode(Toolkit::GradientVisual::SpreadMethod::Type spread)
 {
@@ -162,10 +146,10 @@ void GradientVisual::DoSetProperties(const Property::Map& propertyMap)
     Scripting::GetEnumerationProperty(*unitsValue, UNITS_TABLE, UNITS_TABLE_COUNT, gradientUnits);
   }
 
-  mGradientType = LINEAR;
+  mGradientType = Type::LINEAR;
   if(propertyMap.Find(Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME))
   {
-    mGradientType = RADIAL;
+    mGradientType = Type::RADIAL;
   }
 
   if(NewGradient(mGradientType, propertyMap))
@@ -283,7 +267,7 @@ void GradientVisual::OnInitialize()
 
 bool GradientVisual::NewGradient(Type gradientType, const Property::Map& propertyMap)
 {
-  if(gradientType == LINEAR)
+  if(gradientType == Type::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);
@@ -299,7 +283,7 @@ bool GradientVisual::NewGradient(Type gradientType, const Property::Map& propert
       return false;
     }
   }
-  else // type==RADIAL
+  else // type==Type::RADIAL
   {
     Property::Value* centerValue = propertyMap.Find(Toolkit::GradientVisual::Property::CENTER, CENTER_NAME);
     Property::Value* radiusValue = propertyMap.Find(Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME);
@@ -363,13 +347,57 @@ bool GradientVisual::NewGradient(Type gradientType, const Property::Map& propert
 
 Shader GradientVisual::GetShader()
 {
-  Toolkit::GradientVisual::Units::Type gradientUnits = mGradient->GetGradientUnits();
-  int                                  roundedCorner = IsRoundedCornerRequired() ? 1 : 0;
-  VisualFactoryCache::ShaderType       shaderType    = SHADER_TYPE_TABLE[mGradientType][gradientUnits + roundedCorner * 2];
-  Shader                               shader        = mFactoryCache.GetShader(shaderType);
+  bool userspaceUnit  = (mGradient->GetGradientUnits() == Toolkit::GradientVisual::Units::USER_SPACE);
+  bool roundedCorner  = IsRoundedCornerRequired();
+  bool borderline     = IsBorderlineRequired();
+  bool radialGradient = (mGradientType == Type::RADIAL);
+
+  int  shaderTypeFlag = GradientVisualRequireFlag::DEFAULT;
+  if(roundedCorner)
+  {
+    shaderTypeFlag |= GradientVisualRequireFlag::ROUNDED_CORNER;
+  }
+  if(borderline)
+  {
+    shaderTypeFlag |= GradientVisualRequireFlag::BORDERLINE;
+  }
+  if(userspaceUnit)
+  {
+    shaderTypeFlag |= GradientVisualRequireFlag::USER_SPACE;
+  }
+  if(radialGradient)
+  {
+    shaderTypeFlag |= GradientVisualRequireFlag::RADIAL;
+  }
+
+  VisualFactoryCache::ShaderType shaderType = SHADER_TYPE_TABLE[shaderTypeFlag];
+  Shader                         shader     = mFactoryCache.GetShader(shaderType);
   if(!shader)
   {
-    shader = Shader::New(VERTEX_SHADER[gradientUnits + roundedCorner * 2], FRAGMENT_SHADER[mGradientType + roundedCorner * 2]);
+    std::string vertexShaderPrefixList;
+    std::string fragmentShaderPrefixList;
+
+    if(roundedCorner)
+    {
+      vertexShaderPrefixList   += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+      fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+    }
+    if(borderline)
+    {
+      vertexShaderPrefixList   += "#define IS_REQUIRED_BORDERLINE 1\n";
+      fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
+    }
+    if(radialGradient)
+    {
+      fragmentShaderPrefixList += "#define RADIAL 1\n";
+    }
+    if(userspaceUnit)
+    {
+      vertexShaderPrefixList   += "#define USER_SPACE 1\n";
+    }
+
+    shader = Shader::New(Dali::Shader::GetVertexShaderPrefix()   + vertexShaderPrefixList   + SHADER_GRADIENT_VISUAL_SHADER_VERT.data(),
+                         Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_GRADIENT_VISUAL_SHADER_FRAG.data());
     mFactoryCache.SaveShader(shaderType, shader);
   }
 
index f8f7e5e..7f2cac7 100644 (file)
@@ -50,58 +50,77 @@ ImageVisualShaderFactory::~ImageVisualShaderFactory()
 {
 }
 
-Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping, bool roundedCorner)
+Shader ImageVisualShaderFactory::GetShader(VisualFactoryCache& factoryCache, TextureAtlas atlasing, DefaultTextureWrapMode defaultTextureWrapping, RoundedCorner roundedCorner, Borderline borderline)
 {
   Shader shader;
-  if(atlasing)
+  VisualFactoryCache::ShaderType shaderType = VisualFactoryCache::IMAGE_SHADER;
+  if(atlasing == TextureAtlas::ENABLED)
   {
-    if(defaultTextureWrapping)
+    if(defaultTextureWrapping == DefaultTextureWrapMode::APPLY)
     {
-      shader = factoryCache.GetShader(VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP);
-      if(!shader)
+      shaderType = VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP;
+    }
+    else
+    {
+      shaderType = VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP;
+    }
+  }
+  else
+  {
+    if(roundedCorner == RoundedCorner::ENABLED)
+    {
+      if(borderline == Borderline::ENABLED)
       {
-        shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_VERT.data(),
-                             Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_ATLAS_CLAMP_SHADER_FRAG.data());
-        shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
-        factoryCache.SaveShader(VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP, shader);
+        shaderType = VisualFactoryCache::IMAGE_SHADER_ROUNDED_BORDERLINE;
+      }
+      else
+      {
+        shaderType = VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER;
       }
     }
     else
     {
-      shader = factoryCache.GetShader(VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP);
-      if(!shader)
+      if(borderline == Borderline::ENABLED)
       {
-        shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_VERT.data(),
-                             Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_ATLAS_VARIOUS_WRAP_SHADER_FRAG.data());
-        shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
-        factoryCache.SaveShader(VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP, shader);
+        shaderType = VisualFactoryCache::IMAGE_SHADER_BORDERLINE;
       }
     }
   }
-  else
+
+  shader = factoryCache.GetShader(shaderType);
+  if(!shader)
   {
-    if(roundedCorner)
+    std::string vertexShaderPrefixList;
+    std::string fragmentShaderPrefixList;
+    if(atlasing == TextureAtlas::ENABLED)
     {
-      shader = factoryCache.GetShader(VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER);
-      if(!shader)
+      if(defaultTextureWrapping == DefaultTextureWrapMode::APPLY)
+      {
+        fragmentShaderPrefixList += "#define ATLAS_DEFAULT_WARP 1\n";
+      }
+      else
       {
-        shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_IMAGE_VISUAL_ROUNDED_CORNER_SHADER_VERT.data(),
-                             Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_ROUNDED_CORNER_SHADER_FRAG.data());
-        shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
-        factoryCache.SaveShader(VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER, shader);
+        fragmentShaderPrefixList += "#define ATLAS_CUSTOM_WARP 1\n";
       }
     }
     else
     {
-      shader = factoryCache.GetShader(VisualFactoryCache::IMAGE_SHADER);
-      if(!shader)
+      if(roundedCorner == RoundedCorner::ENABLED)
+      {
+        vertexShaderPrefixList   += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+        fragmentShaderPrefixList += "#define IS_REQUIRED_ROUNDED_CORNER 1\n";
+      }
+      if(borderline == Borderline::ENABLED)
       {
-        shader = Shader::New(Dali::Shader::GetVertexShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_VERT.data(),
-                             Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_NO_ATLAS_SHADER_FRAG.data());
-        shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
-        factoryCache.SaveShader(VisualFactoryCache::IMAGE_SHADER, shader);
+        vertexShaderPrefixList   += "#define IS_REQUIRED_BORDERLINE 1\n";
+        fragmentShaderPrefixList += "#define IS_REQUIRED_BORDERLINE 1\n";
       }
     }
+
+    shader = Shader::New(Dali::Shader::GetVertexShaderPrefix()   + vertexShaderPrefixList   + SHADER_IMAGE_VISUAL_SHADER_VERT.data(),
+                         Dali::Shader::GetFragmentShaderPrefix() + fragmentShaderPrefixList + SHADER_IMAGE_VISUAL_SHADER_FRAG.data());
+    shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
+    factoryCache.SaveShader(shaderType, shader);
   }
 
   return shader;
@@ -121,7 +140,7 @@ std::string_view ImageVisualShaderFactory::GetFragmentShaderSource()
 {
   if(gFragmentShaderNoAtlas.empty())
   {
-    gFragmentShaderNoAtlas = Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_NO_ATLAS_SHADER_FRAG.data();
+    gFragmentShaderNoAtlas = Dali::Shader::GetFragmentShaderPrefix() + SHADER_IMAGE_VISUAL_SHADER_FRAG.data();
   }
   return gFragmentShaderNoAtlas;
 }
index 8ed50a6..604b49b 100644 (file)
@@ -30,11 +30,48 @@ namespace Toolkit
 namespace Internal
 {
 /**
+ * @brief Whether use texture with atlas, or not
+ */
+enum class TextureAtlas
+{
+  DISABLED = 0, ///< Image visual use ATLAS
+  ENABLED       ///< Image visual doesn't use ATLAS
+};
+
+/**
+ * @brief Whether apply to texture wraping in default, or not
+ */
+enum class DefaultTextureWrapMode
+{
+  DO_NOT_APPLY = 0, ///< Image visual doesn't apply to wraping texture in default
+  APPLY             ///< Image visual apply to wraping texture in default
+};
+
+/**
+ * @brief Whether use rounded corner, or not
+ */
+enum class RoundedCorner
+{
+  DISABLED = 0, ///< Image visual doesn't use rounded corner
+  ENABLED       ///< Image visual use rounded corner
+};
+
+/**
+ * @brief Whether use borderline, or not
+ */
+enum class Borderline
+{
+  DISABLED = 0, ///< Image visual doesn't use borderline
+  ENABLED       ///< Image visual use borderline
+};
+
+/**
  * ImageVisualShaderFactory is an object that provides and shares shaders between image visuals
  */
 class ImageVisualShaderFactory
 {
 public:
+
   /**
    * @brief Constructor
    */
@@ -51,8 +88,9 @@ public:
    * @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.
+   * @param[in] borderline Whether the borderline of visual is applied.
    */
-  Shader GetShader(VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping, bool roundedCorner);
+  Shader GetShader(VisualFactoryCache& factoryCache, TextureAtlas atlasing, DefaultTextureWrapMode defaultTextureWrapping, RoundedCorner roundedCorner, Borderline borderline);
 
   /**
    * Request the default vertex shader source.
index 03e0657..bbbab23 100644 (file)
@@ -626,6 +626,10 @@ void ImageVisual::InitializeRenderer()
   if(mTextures)
   {
     mImpl->mRenderer.SetTextures(mTextures);
+    if(DevelTexture::IsNative(mTextures.GetTexture(0)))
+    {
+      UpdateShader();
+    }
     mTextures.Reset(); // Visual should not keep a handle to the texture after this point.
   }
 
@@ -974,9 +978,11 @@ Shader ImageVisual::GetShader()
     // Create and cache the standard shader
     shader = mImageVisualShaderFactory.GetShader(
       mFactoryCache,
-      mImpl->mFlags & Impl::IS_ATLASING_APPLIED,
-      mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE,
-      IsRoundedCornerRequired());
+      mImpl->mFlags & Impl::IS_ATLASING_APPLIED ? TextureAtlas::ENABLED : TextureAtlas::DISABLED,
+      mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE ? DefaultTextureWrapMode::APPLY : DefaultTextureWrapMode::DO_NOT_APPLY,
+      IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
+      IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED
+    );
   }
   else if(mImpl->mCustomShader)
   {
index bb8571d..bbee1d4 100644 (file)
@@ -376,7 +376,13 @@ void NPatchVisual::OnInitialize()
 {
   // Get basic geometry and shader
   Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
-  Shader   shader   = mImageVisualShaderFactory.GetShader(mFactoryCache, false, true, false);
+  Shader   shader   = mImageVisualShaderFactory.GetShader(
+    mFactoryCache,
+    TextureAtlas::DISABLED,
+    DefaultTextureWrapMode::APPLY,
+    RoundedCorner::DISABLED,
+    Borderline::DISABLED
+  );
 
   mImpl->mRenderer = Renderer::New(geometry, shader);
 
index dc148a2..b6f9520 100644 (file)
@@ -87,7 +87,13 @@ void SvgVisual::OnInitialize()
   Shader shader;
   if(!mImpl->mCustomShader)
   {
-    shader = mImageVisualShaderFactory.GetShader(mFactoryCache, mAttemptAtlasing, true, IsRoundedCornerRequired());
+    shader = mImageVisualShaderFactory.GetShader(
+      mFactoryCache,
+      mAttemptAtlasing ? TextureAtlas::ENABLED : TextureAtlas::DISABLED,
+      DefaultTextureWrapMode::APPLY,
+      IsRoundedCornerRequired() ? RoundedCorner::ENABLED : RoundedCorner::DISABLED,
+      IsBorderlineRequired() ? Borderline::ENABLED : Borderline::DISABLED
+    );
   }
   else
   {
index 19e08b2..870ac09 100644 (file)
@@ -528,12 +528,12 @@ void TextVisual::UpdateRenderer()
         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 underlineEnabled       = mController->GetTextModel()->IsUnderlineEnabled();
+      const bool outlineEnabled         = (mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1);
+      const bool backgroundEnabled      = mController->GetTextModel()->IsBackgroundEnabled();
+      const bool markupProcessorEnabled = mController->IsMarkupProcessorEnabled();
 
-      const bool styleEnabled = (shadowEnabled || underlineEnabled || outlineEnabled || backgroundEnabled);
+      const bool styleEnabled = (shadowEnabled || underlineEnabled || outlineEnabled || backgroundEnabled || markupProcessorEnabled);
 
       AddRenderer(control, relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled);
 
index 0d34d55..a449997 100644 (file)
@@ -568,7 +568,8 @@ void TextureManager::Remove(const TextureManager::TextureId textureId, TextureUp
       {
         if(element.mObserver == observer)
         {
-          mLoadQueue.Erase(&element);
+          // Do not erase the item. We will clear it later in ProcessQueuedTextures().
+          element.mObserver = nullptr;
           break;
         }
       }
index 2d42f93..53b5246 100644 (file)
@@ -119,16 +119,23 @@ Internal::Visual::Base::Impl::Impl(FittingMode fittingMode, Toolkit::Visual::Typ
   mTransform(),
   mMixColor(Color::WHITE),
   mControlSize(Vector2::ZERO),
+  mBorderlineWidth(0.0f),
+  mBorderlineColor(Color::BLACK),
+  mBorderlineOffset(0.0f),
   mCornerRadius(Vector4::ZERO),
   mCornerRadiusPolicy(1.0f),
   mDepthIndex(0.0f),
   mMixColorIndex(Property::INVALID_INDEX),
+  mBorderlineWidthIndex(Property::INVALID_INDEX),
+  mBorderlineColorIndex(Property::INVALID_INDEX),
+  mBorderlineOffsetIndex(Property::INVALID_INDEX),
   mCornerRadiusIndex(Property::INVALID_INDEX),
   mFittingMode(fittingMode),
   mFlags(0),
   mResourceStatus(Toolkit::Visual::ResourceStatus::PREPARING),
   mType(type),
-  mNeedCornerRadius(false)
+  mNeedCornerRadius(false),
+  mNeedBorderline(false)
 {
 }
 
index acb6805..52e0d98 100644 (file)
@@ -123,16 +123,23 @@ struct Base::Impl
   Transform                       mTransform;
   Vector4                         mMixColor;
   Size                            mControlSize;
+  float                           mBorderlineWidth;
+  Vector4                         mBorderlineColor;
+  float                           mBorderlineOffset;
   Vector4                         mCornerRadius;
   float                           mCornerRadiusPolicy;
   int                             mDepthIndex;
   Property::Index                 mMixColorIndex;
+  Property::Index                 mBorderlineWidthIndex;
+  Property::Index                 mBorderlineColorIndex;
+  Property::Index                 mBorderlineOffsetIndex;
   Property::Index                 mCornerRadiusIndex;
   FittingMode                     mFittingMode; //< How the contents should fit the view
   int                             mFlags;
   Toolkit::Visual::ResourceStatus mResourceStatus;
   const Toolkit::Visual::Type     mType;
   bool                            mNeedCornerRadius;
+  bool                            mNeedBorderline;
 };
 
 } // namespace Visual
index 528bc14..49b3120 100644 (file)
@@ -89,6 +89,14 @@ void Visual::Base::Initialize()
 
       mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
     }
+    if(IsBorderlineRequired())
+    {
+      mImpl->mBorderlineWidthIndex  = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_WIDTH,  BORDERLINE_WIDTH,  mImpl->mBorderlineWidth);
+      mImpl->mBorderlineColorIndex  = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_COLOR,  BORDERLINE_COLOR,  mImpl->mBorderlineColor);
+      mImpl->mBorderlineOffsetIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_OFFSET, BORDERLINE_OFFSET, mImpl->mBorderlineOffset);
+
+      mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
+    }
   }
 }
 
@@ -142,6 +150,18 @@ void Visual::Base::SetProperties(const Property::Map& propertyMap)
       {
         matchKey = Property::Key(Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE);
       }
+      else if(matchKey == BORDERLINE_WIDTH)
+      {
+        matchKey = Property::Key(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH);
+      }
+      else if(matchKey == BORDERLINE_COLOR)
+      {
+        matchKey = Property::Key(Toolkit::DevelVisual::Property::BORDERLINE_COLOR);
+      }
+      else if(matchKey == BORDERLINE_OFFSET)
+      {
+        matchKey = Property::Key(Toolkit::DevelVisual::Property::BORDERLINE_OFFSET);
+      }
       else if(matchKey == CORNER_RADIUS)
       {
         matchKey = Property::Key(Toolkit::DevelVisual::Property::CORNER_RADIUS);
@@ -217,6 +237,33 @@ void Visual::Base::SetProperties(const Property::Map& propertyMap)
           value, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT, mImpl->mFittingMode);
         break;
       }
+      case Toolkit::DevelVisual::Property::BORDERLINE_WIDTH:
+      {
+        float width;
+        if(value.Get(width))
+        {
+          mImpl->mBorderlineWidth = width;
+        }
+        break;
+      }
+      case Toolkit::DevelVisual::Property::BORDERLINE_COLOR:
+      {
+        Vector4 color;
+        if(value.Get(color))
+        {
+          mImpl->mBorderlineColor = color;
+        }
+        break;
+      }
+      case Toolkit::DevelVisual::Property::BORDERLINE_OFFSET:
+      {
+        float offset;
+        if(value.Get(offset))
+        {
+          mImpl->mBorderlineOffset = offset;
+        }
+        break;
+      }
       case Toolkit::DevelVisual::Property::CORNER_RADIUS:
       {
         if(value.GetType() == Property::VECTOR4)
@@ -388,6 +435,18 @@ void Visual::Base::CreatePropertyMap(Property::Map& map) const
     {
       mImpl->mCornerRadius = mImpl->mRenderer.GetProperty<Vector4>(mImpl->mCornerRadiusIndex);
     }
+    if(mImpl->mBorderlineWidthIndex != Property::INVALID_INDEX)
+    {
+      mImpl->mBorderlineWidth = mImpl->mRenderer.GetProperty<float>(mImpl->mBorderlineWidthIndex);
+    }
+    if(mImpl->mBorderlineColorIndex != Property::INVALID_INDEX)
+    {
+      mImpl->mBorderlineColor = mImpl->mRenderer.GetProperty<Vector4>(mImpl->mBorderlineColorIndex);
+    }
+    if(mImpl->mBorderlineOffsetIndex != Property::INVALID_INDEX)
+    {
+      mImpl->mBorderlineOffset = mImpl->mRenderer.GetProperty<float>(mImpl->mBorderlineOffsetIndex);
+    }
   }
 
   DoCreatePropertyMap(map);
@@ -413,6 +472,10 @@ void Visual::Base::CreatePropertyMap(Property::Map& map) const
     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::BORDERLINE_WIDTH, mImpl->mBorderlineWidth);
+  map.Insert(Toolkit::DevelVisual::Property::BORDERLINE_COLOR, mImpl->mBorderlineColor);
+  map.Insert(Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, mImpl->mBorderlineOffset);
+
   map.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, mImpl->mCornerRadius);
   map.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS_POLICY, static_cast<int>(mImpl->mCornerRadiusPolicy));
 }
@@ -470,6 +533,16 @@ bool Visual::Base::IsRoundedCornerRequired() const
   return !(mImpl->mCornerRadius == Vector4::ZERO) || mImpl->mNeedCornerRadius;
 }
 
+bool Visual::Base::IsBorderlineRequired() const
+{
+  if(mImpl->mRenderer && mImpl->mBorderlineWidthIndex != Property::INVALID_INDEX)
+  {
+    // Update values from Renderer
+    mImpl->mBorderlineWidth = mImpl->mRenderer.GetProperty<float>(mImpl->mBorderlineWidthIndex);
+  }
+  return !EqualsZero(mImpl->mBorderlineWidth) || mImpl->mNeedBorderline;
+}
+
 void Visual::Base::OnDoAction(const Property::Index actionId, const Property::Value& attributes)
 {
   // May be overriden by derived class
@@ -824,7 +897,24 @@ Dali::Property Visual::Base::GetPropertyObject(Dali::Property::Key key)
   Property::Index index = GetPropertyIndex(key);
   if(index == Property::INVALID_INDEX)
   {
-    if((key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::CORNER_RADIUS) || (key.type == Property::Key::STRING && key.stringKey == CORNER_RADIUS))
+    if((key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::BORDERLINE_WIDTH)  || (key.type == Property::Key::STRING && key.stringKey == BORDERLINE_WIDTH) ||
+       (key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::BORDERLINE_COLOR)  || (key.type == Property::Key::STRING && key.stringKey == BORDERLINE_COLOR) ||
+       (key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::BORDERLINE_OFFSET) || (key.type == Property::Key::STRING && key.stringKey == BORDERLINE_OFFSET))
+    {
+      mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
+
+      // Register borderline properties
+      mImpl->mBorderlineWidthIndex  = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_WIDTH, BORDERLINE_WIDTH, mImpl->mBorderlineWidth);
+      mImpl->mBorderlineColorIndex  = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_COLOR, BORDERLINE_COLOR, mImpl->mBorderlineColor);
+      mImpl->mBorderlineOffsetIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::BORDERLINE_OFFSET, BORDERLINE_OFFSET, mImpl->mBorderlineOffset);
+      mImpl->mNeedBorderline        = true;
+
+      index = mImpl->mRenderer.GetPropertyIndex(key);
+
+      // Change shader
+      UpdateShader();
+    }
+    else if((key.type == Property::Key::INDEX && key.indexKey == DevelVisual::Property::CORNER_RADIUS) || (key.type == Property::Key::STRING && key.stringKey == CORNER_RADIUS))
     {
       // Register CORNER_RADIUS property
       mImpl->mCornerRadiusIndex = mImpl->mRenderer.RegisterProperty(DevelVisual::Property::CORNER_RADIUS, CORNER_RADIUS, mImpl->mCornerRadius);
index c958992..8800ad8 100644 (file)
@@ -389,6 +389,13 @@ protected:
    */
   bool IsRoundedCornerRequired() const;
 
+  /**
+   * @brief Query whether the borderline of the visual requires to be rendered.
+   *
+   * @return Returns true if the outline is required, false otherwise.
+   */
+  bool IsBorderlineRequired() const;
+
 private:
   /**
    * Register the mix color uniform on the Renderer and store the property index.
index 418b10e..6e8f37d 100644 (file)
@@ -57,21 +57,34 @@ public:
   {
     COLOR_SHADER,
     COLOR_SHADER_ROUNDED_CORNER,
+    COLOR_SHADER_BORDERLINE,
+    COLOR_SHADER_ROUNDED_BORDERLINE,
     COLOR_SHADER_BLUR_EDGE,
+    COLOR_SHADER_ROUNDED_CORNER_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,
-    GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_CORNER,
     GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_CORNER,
-    GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_CORNER,
+    GRADIENT_SHADER_LINEAR_BOUNDING_BOX_BORDERLINE,
+    GRADIENT_SHADER_LINEAR_BOUNDING_BOX_ROUNDED_BORDERLINE,
+    GRADIENT_SHADER_LINEAR_USER_SPACE,
+    GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_CORNER,
+    GRADIENT_SHADER_LINEAR_USER_SPACE_BORDERLINE,
+    GRADIENT_SHADER_LINEAR_USER_SPACE_ROUNDED_BORDERLINE,
+    GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
     GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_CORNER,
+    GRADIENT_SHADER_RADIAL_BOUNDING_BOX_BORDERLINE,
+    GRADIENT_SHADER_RADIAL_BOUNDING_BOX_ROUNDED_BORDERLINE,
+    GRADIENT_SHADER_RADIAL_USER_SPACE,
+    GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_CORNER,
+    GRADIENT_SHADER_RADIAL_USER_SPACE_BORDERLINE,
+    GRADIENT_SHADER_RADIAL_USER_SPACE_ROUNDED_BORDERLINE,
     IMAGE_SHADER,
     IMAGE_SHADER_ATLAS_DEFAULT_WRAP,
     IMAGE_SHADER_ATLAS_CUSTOM_WRAP,
     IMAGE_SHADER_ROUNDED_CORNER,
+    IMAGE_SHADER_BORDERLINE,
+    IMAGE_SHADER_ROUNDED_BORDERLINE,
     NINE_PATCH_SHADER,
     NINE_PATCH_MASK_SHADER,
     TEXT_SHADER_MULTI_COLOR_TEXT,
index 8c4b2f8..6bbc2df 100644 (file)
@@ -166,6 +166,7 @@ Toolkit::Visual::Base VisualFactory::CreateVisual(const Property::Map& propertyM
                 break;
               }
               case VisualUrl::JSON:
+              case VisualUrl::RIVE:
               {
                 visualPtr = AnimatedVectorImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), imageUrl, propertyMap);
                 break;
@@ -330,6 +331,7 @@ Toolkit::Visual::Base VisualFactory::CreateVisual(const std::string& url, ImageD
         break;
       }
       case VisualUrl::JSON:
+      case VisualUrl::RIVE:
       {
         visualPtr = AnimatedVectorImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl);
         break;
index 9f1ad0a..53bcd1c 100644 (file)
@@ -75,12 +75,16 @@ const char* const OPACITY("opacity");
 // Fitting mode
 const char* const VISUAL_FITTING_MODE("visualFittingMode");
 
+// Border line
+const char* const BORDERLINE_WIDTH("borderlineWidth");
+const char* const BORDERLINE_COLOR("borderlineColor");
+const char* const BORDERLINE_OFFSET("borderlineOffset");
+
 // Corner radius
 const char* const CORNER_RADIUS("cornerRadius");
 const char* const CORNER_RADIUS_POLICY("cornerRadiusPolicy");
 
 // Color visual
-const char* const RENDER_IF_TRANSPARENT_NAME("renderIfTransparent");
 const char* const BLUR_RADIUS_NAME("blurRadius");
 
 // Image visual
index 5f7f336..470ded9 100644 (file)
@@ -59,12 +59,16 @@ extern const char* const OPACITY;
 // Fitting mode
 extern const char* const VISUAL_FITTING_MODE;
 
+// Border line
+extern const char* const BORDERLINE_WIDTH;
+extern const char* const BORDERLINE_COLOR;
+extern const char* const BORDERLINE_OFFSET;
+
 // Corner radius
 extern const char* const CORNER_RADIUS;
 extern const char* const CORNER_RADIUS_POLICY;
 
 // Color visual
-extern const char* const RENDER_IF_TRANSPARENT_NAME;
 extern const char* const BLUR_RADIUS_NAME;
 
 // Image visual
index e498313..97bc9b9 100644 (file)
@@ -103,10 +103,12 @@ VisualUrl::Type ResolveType(const std::string& url)
     char         GIF[4]    = {'f', 'i', 'g', '.'};
     char         WEBP[5]   = {'p', 'b', 'e', 'w', '.'};
     char         JSON[5]   = {'n', 'o', 's', 'j', '.'};
+    char         RIVE[4]   = {'v', 'i', 'r', '.'};
     unsigned int svgScore  = 0;
     unsigned int gifScore  = 0;
     unsigned int webpScore = 0;
     unsigned int jsonScore = 0;
+    unsigned int riveScore = 0;
     int          index     = count;
     while(--index >= 0)
     {
@@ -144,6 +146,14 @@ VisualUrl::Type ResolveType(const std::string& url)
           return VisualUrl::JSON;
         }
       }
+      if((offsetFromEnd < sizeof(RIVE)) && (currentChar == RIVE[offsetFromEnd]))
+      {
+        // early out if RIVE as can't be used in N patch for now
+        if(++riveScore == sizeof(RIVE))
+        {
+          return VisualUrl::RIVE;
+        }
+      }
       switch(state)
       {
         case SUFFIX:
index 8857184..827dfce 100644 (file)
@@ -38,7 +38,8 @@ public:
     SVG,
     GIF,
     WEBP,
-    JSON
+    JSON,
+    RIVE
   };
 
   enum ProtocolType
index 62b1079..17db11b 100644 (file)
@@ -64,27 +64,6 @@ Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_CON
 #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 && backgroundVisual.GetType() == Toolkit::Visual::COLOR)
-  {
-    Property::Map map;
-    backgroundVisual.CreatePropertyMap(map);
-
-    // 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.
@@ -96,34 +75,11 @@ void CreateClippingRenderer(Control& controlImpl)
   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;
-      }
+    Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(controlImpl);
 
-      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;
-      }
+    if(clippingMode == ClippingMode::CLIP_CHILDREN && controlDataImpl.mVisuals.Empty() && self.GetRendererCount() == 0u)
+    {
+      controlImpl.SetBackgroundColor(Color::TRANSPARENT);
     }
   }
 }
@@ -173,33 +129,12 @@ void Control::SetBackgroundColor(const Vector4& color)
   map[Toolkit::Visual::Property::TYPE]           = Toolkit::Visual::COLOR;
   map[Toolkit::ColorVisual::Property::MIX_COLOR] = color;
 
-  bool renderIfTransparent = false;
-  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;
-    renderIfTransparent                                             = true;
-  }
-
   Toolkit::Visual::Base visual = mImpl->GetVisual(Toolkit::Control::Property::BACKGROUND);
   if(visual && visual.GetType() == Toolkit::Visual::COLOR)
   {
-    Property::Map visualMap;
-    visual.CreatePropertyMap(visualMap);
-
-    Property::Value* renderValue = visualMap.Find(Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT);
-    Property::Value* colorValue  = visualMap.Find(Toolkit::ColorVisual::Property::MIX_COLOR);
-    if(renderValue && colorValue)
-    {
-      if((renderValue->Get<bool>() == true || colorValue->Get<Vector4>().a > 0.0f) && (renderIfTransparent || color.a > 0.0f))
-      {
-        // Update background color only
-        mImpl->DoAction(Toolkit::Control::Property::BACKGROUND, DevelColorVisual::Action::UPDATE_PROPERTY, map);
-        return;
-      }
-    }
+    // Update background color only
+    mImpl->DoAction(Toolkit::Control::Property::BACKGROUND, DevelColorVisual::Action::UPDATE_PROPERTY, map);
+    return;
   }
 
   SetBackground(map);
@@ -492,11 +427,8 @@ void Control::Initialize()
   if(type)
   {
     auto typeName = type.GetName();
-    DevelControl::AppendAccessibilityAttribute(Self(), "t", typeName);
+    DevelControl::AppendAccessibilityAttribute(Self(), "class", typeName);
   }
-
-  if(Accessibility::IsUp())
-    mImpl->AccessibilityRegister();
 }
 
 void Control::OnInitialize()
@@ -592,21 +524,10 @@ void Control::OnSceneConnection(int depth)
 
   // The clipping renderer is only created if required.
   CreateClippingRenderer(*this);
-
-  // Request to be laid out when the control is connected to the Scene.
-  // Signal that a Relayout may be needed
-  if(Accessibility::IsUp())
-  {
-    mImpl->AccessibilityRegister();
-  }
 }
 
 void Control::OnSceneDisconnection()
 {
-  if(Accessibility::IsUp())
-  {
-    mImpl->AccessibilityDeregister(true);
-  }
   mImpl->OnSceneDisconnection();
 }
 
index 51e26f7..71589e0 100644 (file)
@@ -138,7 +138,8 @@ public:
     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
+    JUSTIFY_SPACE_AROUND,  ///< Items are positioned with equal space before, and after the lines @SINCE_1_1.35
+    JUSTIFY_SPACE_EVENLY   ///< Items are positioned with equal space before, between, and after the lines @SINCE_2_0.29
   };
 
   /**
index 2f475a2..7b6f6ca 100644 (file)
@@ -29,7 +29,7 @@ namespace Toolkit
 {
 const unsigned int TOOLKIT_MAJOR_VERSION = 2;
 const unsigned int TOOLKIT_MINOR_VERSION = 0;
-const unsigned int TOOLKIT_MICRO_VERSION = 23;
+const unsigned int TOOLKIT_MICRO_VERSION = 29;
 const char* const  TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 4552527..df6b9e4 100644 (file)
@@ -115,7 +115,8 @@ The possible values for this property are:
 | 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 |
+| JUSTIFY_SPACE_AROUND    | Items are positioned with equal space before, and after the lines          |
+| JUSTIFY_SPACE_EVENLY    | Items are positioned with equal space before, between, and after the lines |
  
 ### Usage
 
index ba6c2b6..3afd7e5 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    2.0.23
+Version:    2.0.29
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT