Merge "Do not clear keyboard focus on touch when alwaysShowFocus is true." into devel...
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Mon, 18 Sep 2017 10:30:56 +0000 (10:30 +0000)
committerGerrit Code Review <gerrit@review.ap-northeast-2.compute.internal>
Mon, 18 Sep 2017 10:30:56 +0000 (10:30 +0000)
50 files changed:
automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-VisualUrl.cpp
automated-tests/src/dali-toolkit/CMakeLists.txt
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-harness.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextureManager.cpp [new file with mode: 0644]
build/tizen/Makefile.am
dali-toolkit/devel-api/file.list
dali-toolkit/devel-api/image-loader/texture-manager.cpp [new file with mode: 0644]
dali-toolkit/devel-api/image-loader/texture-manager.h [new file with mode: 0644]
dali-toolkit/devel-api/visuals/text-visual-properties.h
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/controls/text-controls/text-label-impl.h
dali-toolkit/internal/controls/video-view/video-view-impl.cpp
dali-toolkit/internal/file.list
dali-toolkit/internal/image-loader/image-load-thread.cpp
dali-toolkit/internal/text/rendering/text-typesetter.cpp
dali-toolkit/internal/text/rendering/text-typesetter.h
dali-toolkit/internal/text/rendering/view-model.cpp
dali-toolkit/internal/text/rendering/view-model.h
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-controller.h
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-scroller.cpp
dali-toolkit/internal/text/text-scroller.h
dali-toolkit/internal/text/text-view.cpp
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-image/fixed-image-cache.h
dali-toolkit/internal/visuals/animated-image/image-cache.h
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.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/text/text-visual.h
dali-toolkit/internal/visuals/texture-manager-impl.cpp [moved from dali-toolkit/internal/visuals/texture-manager.cpp with 95% similarity]
dali-toolkit/internal/visuals/texture-manager-impl.h [moved from dali-toolkit/internal/visuals/texture-manager.h with 94% similarity]
dali-toolkit/internal/visuals/visual-factory-cache.h
dali-toolkit/internal/visuals/visual-factory-impl.cpp
dali-toolkit/internal/visuals/visual-factory-impl.h
dali-toolkit/internal/visuals/visual-url.cpp
dali-toolkit/internal/visuals/visual-url.h
dali-toolkit/public-api/controls/text-controls/text-label.h
dali-toolkit/public-api/dali-toolkit-version.cpp

index 2d06a44..24c5c5d 100644 (file)
@@ -20,7 +20,7 @@
 #include <stdlib.h>
 
 #include <dali-toolkit-test-suite-utils.h>
-#include <dali-toolkit/internal/visuals/texture-manager.h>
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
 #include <dali-toolkit/internal/visuals/texture-upload-observer.h>
 
 using namespace Dali::Toolkit::Internal;
index 476a023..962ad8e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,22 +26,22 @@ using namespace Dali::Toolkit::Internal;
 
 int UtcDaliVisualUrlConstructor(void)
 {
-  const char* url="http://bar.org/foobar.gif";
+  const char* url="file://bar.org/foobar.gif";
   VisualUrl visualUrl(url);
   DALI_TEST_EQUALS( true, visualUrl.IsValid(), TEST_LOCATION );
   DALI_TEST_EQUALS( visualUrl.GetType(), VisualUrl::GIF, TEST_LOCATION );
-  DALI_TEST_EQUALS( visualUrl.GetLocation(), VisualUrl::REMOTE, TEST_LOCATION );
+  DALI_TEST_EQUALS( visualUrl.GetProtocolType(), VisualUrl::LOCAL, TEST_LOCATION );
 
   VisualUrl visualUrl2("foobar.jpeg");
   visualUrl2 = visualUrl;
   DALI_TEST_EQUALS( true, visualUrl2.IsValid(), TEST_LOCATION );
   DALI_TEST_EQUALS( visualUrl2.GetType(), VisualUrl::GIF, TEST_LOCATION );
-  DALI_TEST_EQUALS( visualUrl2.GetLocation(), VisualUrl::REMOTE, TEST_LOCATION );
+  DALI_TEST_EQUALS( visualUrl2.GetProtocolType(), VisualUrl::LOCAL, TEST_LOCATION );
 
   VisualUrl visualUrl3( visualUrl );
   DALI_TEST_EQUALS( true, visualUrl3.IsValid(), TEST_LOCATION );
   DALI_TEST_EQUALS( visualUrl3.GetType(), VisualUrl::GIF, TEST_LOCATION );
-  DALI_TEST_EQUALS( visualUrl3.GetLocation(), VisualUrl::REMOTE, TEST_LOCATION );
+  DALI_TEST_EQUALS( visualUrl3.GetProtocolType(), VisualUrl::LOCAL, TEST_LOCATION );
   END_TEST;
 }
 
@@ -66,6 +66,8 @@ int UtcDaliVisualUrlRegularImage(void)
 
   DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("9").GetType(), TEST_LOCATION );
 
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("dali://bar.org/foobar.gif").GetType(), TEST_LOCATION );
+
   END_TEST;
 }
 
@@ -132,6 +134,7 @@ int UtcDaliVisualUrlGif(void)
 
   DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("gif.png").GetType(), TEST_LOCATION );
   DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("gif.gif1").GetType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("dali://.gif").GetType(), TEST_LOCATION );
 
   END_TEST;
 }
@@ -141,65 +144,82 @@ int UtcDaliVisualUrlLocationP(void)
 {
   tet_infoline( "UtcDaliVisualUrl Location" );
 
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("foobar.gif").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("foobar.png").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("foobar.svg").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("foobar.GIF").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("foobar.9.png").GetLocation(), TEST_LOCATION );
-
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.gif").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.png").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.svg").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.jpeg").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.9.png").GetLocation(), TEST_LOCATION );
-
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://bar.org/foobar.gif").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://bar.org/foobar.png").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://bar.org/foobar.svg").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://bar.org/foobar.GIF").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://bar.org/foobar.9.png").GetLocation(), TEST_LOCATION );
-
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://bar.org/foobar.gif").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://bar.org/foobar.png").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://bar.org/foobar.svg").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://bar.org/foobar.GIF").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://bar.org/foobar.9.png").GetLocation(), TEST_LOCATION );
-
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://bar.org/foobar.gif").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://bar.org/foobar.png").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://bar.org/foobar.svg").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://bar.org/foobar.GIF").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://bar.org/foobar.9.png").GetLocation(), TEST_LOCATION );
-
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://bar.org/foobar.gif").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://bar.org/foobar.png").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://bar.org/foobar.svg").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://bar.org/foobar.GIF").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://bar.org/foobar.9.png").GetLocation(), TEST_LOCATION );
-
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://bar.org/foobar.gif").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://bar.org/foobar.png").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://bar.org/foobar.svg").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://bar.org/foobar.GIF").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://BAR.ORG/foobar.9.png").GetLocation(), TEST_LOCATION );
-
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://bar.org/foobar.gif").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://bar.org/foobar.png").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://bar.org/foobar.svg").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://bar.org/foobar.GIF").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://BAR.ORG/foobar.9.png").GetLocation(), TEST_LOCATION );
-
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://bar.org/foobar.gif").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://bar.org/foobar.png").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://bar.org/foobar.svg").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://bar.org/foobar.GIF").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://bar.org/foobar.9.png").GetLocation(), TEST_LOCATION );
-
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://bar.org/foobar.gif").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://bar.org/foobar.png").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://bar.org/foobar.svg").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://bar.org/foobar.GIF").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://bar.org/foobar.9.png").GetLocation(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.jpeg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://bar.org/foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://bar.org/foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://bar.org/foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://bar.org/foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://bar.org/foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://BAR.ORG/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://bar.org/foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://BAR.ORG/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://bar.org/foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://bar.org/foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("dali://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("dali://1234").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("DALI://1234").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("dali://.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("dali://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("dali://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("dali://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("dali://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
 
   END_TEST;
 }
@@ -209,63 +229,48 @@ int UtcDaliVisualUrlLocationN(void)
 {
   tet_infoline( "UtcDaliVisualUrl Location negative tests" );
 
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("htp://bar.org/foobar.gif").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("htpp://bar.org/foobar.png").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("sshttp://bar.org/foobar.svg").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("htth://bar.org/foobar.GIF").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("http:https://bar.org/foobar.9.png").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("https:http://bar.org/foobar.9.png").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("HPPT://bar.org/foobar.gif").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ftp:/bar.org/foobar.9.png").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ssh;//bar.org/foobar.9.png").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ssh:/bar.org/foobar.9.png").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("http:/bar.org/foobar.gif").GetLocation(), TEST_LOCATION );
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("https:/bar.org/foobar.gif").GetLocation(), TEST_LOCATION );
-
-  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.png").GetLocation(), TEST_LOCATION );
-
-  END_TEST;
-}
-
-
-int UtcDaliVisualUrlIsLocal(void)
-{
-  tet_infoline( "UtcDaliVisualUrl IsLocal" );
-
-  DALI_TEST_EQUALS( true, VisualUrl("foobar.gif").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( true, VisualUrl("foobar.png").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( true, VisualUrl("foobar.svg").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( true, VisualUrl("foobar.GIF").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( true, VisualUrl("foobar.9.png").IsLocal(), TEST_LOCATION );
-
-  DALI_TEST_EQUALS( false, VisualUrl("http://bar.org/foobar.gif").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( false, VisualUrl("http://bar.org/foobar.png").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( false, VisualUrl("http://bar.org/foobar.svg").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( false, VisualUrl("http://bar.org/foobar.GIF").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( false, VisualUrl("http://bar.org/foobar.9.png").IsLocal(), TEST_LOCATION );
-
-  DALI_TEST_EQUALS( false, VisualUrl("https://bar.org/foobar.gif").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( false, VisualUrl("https://bar.org/foobar.png").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( false, VisualUrl("https://bar.org/foobar.svg").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( false, VisualUrl("https://bar.org/foobar.GIF").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( false, VisualUrl("https://bar.org/foobar.9.png").IsLocal(), TEST_LOCATION );
-
-  DALI_TEST_EQUALS( false, VisualUrl("HTTP://bar.org/foobar.gif").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( false, VisualUrl("HTTP://bar.org/foobar.png").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( false, VisualUrl("HTTP://bar.org/foobar.svg").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( false, VisualUrl("HTTP://bar.org/foobar.GIF").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( false, VisualUrl("HTTP://bar.org/foobar.9.png").IsLocal(), TEST_LOCATION );
-
-  DALI_TEST_EQUALS( false, VisualUrl("HTTPS://bar.org/foobar.gif").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( false, VisualUrl("HTTPS://bar.org/foobar.png").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( false, VisualUrl("HTTPS://bar.org/foobar.svg").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( false, VisualUrl("HTTPS://bar.org/foobar.GIF").IsLocal(), TEST_LOCATION );
-  DALI_TEST_EQUALS( false, VisualUrl("HTTPS://bar.org/foobar.9.png").IsLocal(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("h://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ht://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("htp://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("htpp://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("httt://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("http;//bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("http:x/bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("http:/xbar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("sshttp://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("http:https://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("https:http://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("HPPT://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ftp:/bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ftp:a/bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("fpp://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ftt://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ssh;//bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ssh:/bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ssh:a/bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("shh://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("sss://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("http:/bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("h1tps://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ht2ps://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("htt3s://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("http4://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("https5/bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("https:6/bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("https:/7bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("dal://1").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("d1li://1").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("da2i://1").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("dal3://1").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("dali4//1").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("dali:5/1").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("dali:/61").GetProtocolType(), TEST_LOCATION );
 
   END_TEST;
 }
 
-
 int UtcDaliVisualUrlIsValid(void)
 {
   tet_infoline( "UtcDaliVisualUrl IsValid" );
@@ -305,3 +310,77 @@ int UtcDaliVisualUrlIsValid(void)
 
   END_TEST;
 }
+
+
+int UtcDaliVisualUrlIsLocalResource(void)
+{
+  tet_infoline( "UtcDaliVisualUrl IsLocalResource" );
+
+  DALI_TEST_EQUALS( true, VisualUrl("foobar.gif").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("foobar.png").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("foobar.svg").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("foobar.GIF").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("foobar.9.png").IsLocalResource(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( false, VisualUrl("http://bar.org/foobar.gif").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("http://bar.org/foobar.png").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("http://bar.org/foobar.svg").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("http://bar.org/foobar.GIF").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("http://bar.org/foobar.9.png").IsLocalResource(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( false, VisualUrl("https://bar.org/foobar.gif").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("https://bar.org/foobar.png").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("https://bar.org/foobar.svg").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("https://bar.org/foobar.GIF").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("https://bar.org/foobar.9.png").IsLocalResource(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( false, VisualUrl("HTTP://bar.org/foobar.gif").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("HTTP://bar.org/foobar.png").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("HTTP://bar.org/foobar.svg").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("HTTP://bar.org/foobar.GIF").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("HTTP://bar.org/foobar.9.png").IsLocalResource(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( false, VisualUrl("HTTPS://bar.org/foobar.gif").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("HTTPS://bar.org/foobar.png").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("HTTPS://bar.org/foobar.svg").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("HTTPS://bar.org/foobar.GIF").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("HTTPS://bar.org/foobar.9.png").IsLocalResource(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualUrlGetLocationP(void)
+{
+  tet_infoline( "UtcDaliVisualUrl GetLocation Positive" );
+
+  DALI_TEST_EQUAL( "a", VisualUrl("http://a").GetLocation() );
+  DALI_TEST_EQUAL( "1", VisualUrl("dali://1").GetLocation() );
+  DALI_TEST_EQUAL( "", VisualUrl("ftp://").GetLocation() );
+  DALI_TEST_EQUAL( "http://", VisualUrl("http://http://").GetLocation() );
+
+  END_TEST;
+}
+
+int UtcDaliVisualUrlGetLocationN(void)
+{
+  tet_infoline( "UtcDaliVisualUrl GetLocation Negative" );
+
+  DALI_TEST_EQUAL( "", VisualUrl("").GetLocation() );
+  DALI_TEST_EQUAL( "a", VisualUrl("a").GetLocation() );
+  DALI_TEST_EQUAL( "dali:/1", VisualUrl("dali:/1").GetLocation() );
+  DALI_TEST_EQUAL( "dali//1", VisualUrl("dali//1").GetLocation() );
+  DALI_TEST_EQUAL( "", VisualUrl("http:/http://").GetLocation() );
+
+  END_TEST;
+}
+
+int UtcDaliVisualUrlCreateTextureUrl(void)
+{
+  tet_infoline( "UtcDaliVisualUrl CreateTextureUrl" );
+
+  DALI_TEST_EQUAL( "dali://a", VisualUrl::CreateTextureUrl( "a" ) );
+  DALI_TEST_EQUAL( "dali://1234", VisualUrl::CreateTextureUrl( "1234" ) );
+  DALI_TEST_EQUAL( "dali://", VisualUrl::CreateTextureUrl( "" ) );
+
+  END_TEST;
+}
index d3b5bba..4def66d 100755 (executable)
@@ -36,6 +36,7 @@ SET(TC_SOURCES
    utc-Dali-TextSelectionPopup.cpp
    utc-Dali-TextSelectionPopupMirroringLTR.cpp
    utc-Dali-TextSelectionPopupMirroringRTL.cpp
+   utc-Dali-TextureManager.cpp
    utc-Dali-ToolBar.cpp
    utc-Dali-Tooltip.cpp
    utc-Dali-TransitionData.cpp
index 8877a50..b38428b 100644 (file)
@@ -117,6 +117,7 @@ void DALI_TEST_EQUALS( const Matrix3& matrix1, const Matrix3& matrix2, const cha
                m1[6],  m1[7], m1[8],   m2[6],  m2[7], m2[8]);
 
     tet_result(TET_FAIL);
+    throw("TET_FAIL");
   }
   else
   {
@@ -147,6 +148,7 @@ void DALI_TEST_EQUALS( const Matrix3& matrix1, const Matrix3& matrix2, float eps
                m1[6],  m1[7], m1[8],   m2[6],  m2[7], m2[8]);
 
     tet_result(TET_FAIL);
+    throw("TET_FAIL");
   }
   else
   {
@@ -183,6 +185,7 @@ void DALI_TEST_EQUALS( const Matrix& matrix1, const Matrix& matrix2, const char*
               m1[12], m1[13], m1[14], m1[15],  m2[12], m2[13], m2[14], m2[15]);
 
     tet_result(TET_FAIL);
+    throw("TET_FAIL");
   }
   else
   {
@@ -214,6 +217,7 @@ void DALI_TEST_EQUALS( const Matrix& matrix1, const Matrix& matrix2, float epsil
               m1[12], m1[13], m1[14], m1[15],  m2[12], m2[13], m2[14], m2[15]);
 
     tet_result(TET_FAIL);
+    throw("TET_FAIL");
   }
   else
   {
@@ -251,6 +255,7 @@ void DALI_TEST_EQUALS( Property::Value& str1, const char* str2, const char* loca
   else
   {
     tet_result(TET_FAIL);
+    throw("TET_FAIL");
   }
 }
 
@@ -265,6 +270,7 @@ void DALI_TEST_ASSERT( DaliException& e, std::string conditionSubString, const c
   {
     fprintf(stderr, "Expected substring '%s' : actual exception string '%s' : location %s\n", conditionSubString.c_str(), e.condition, location );
     tet_result(TET_FAIL);
+    throw("TET_FAIL");
   }
   else
   {
@@ -294,6 +300,7 @@ void ConstraintAppliedCheck::CheckSignalReceived()
   {
     fprintf(stderr,  "Expected Applied signal was not received\n" );
     tet_result( TET_FAIL );
+    throw("TET_FAIL");
   }
   else
   {
@@ -307,6 +314,7 @@ void ConstraintAppliedCheck::CheckSignalNotReceived()
   {
     fprintf(stderr,  "Unexpected Applied signal was received\n" );
     tet_result( TET_FAIL );
+    throw("TET_FAIL");
   }
   else
   {
index 2b84d39..4f71920 100644 (file)
@@ -40,11 +40,24 @@ using namespace Dali;
 #define STRINGIZE_I(text) #text
 #define STRINGIZE(text) STRINGIZE_I(text)
 
-// the following is the other compilers way of token pasting, gcc seems to just concatenate strings automatically
-//#define TOKENPASTE(x,y) x ## y
-#define TOKENPASTE(x,y) x y
-#define TOKENPASTE2(x,y) TOKENPASTE( x, y )
-#define TEST_LOCATION TOKENPASTE2( "Test failed in ", TOKENPASTE2( __FILE__, TOKENPASTE2( ", line ", STRINGIZE(__LINE__) ) ) )
+/**
+ * Inspired by https://stackoverflow.com/questions/1706346/file-macro-manipulation-handling-at-compile-time
+ * answer by Chetan Reddy
+ */
+constexpr int32_t basenameIndex( const char * const path, const int32_t index = 0, const int32_t slashIndex = -1 )
+{
+   return path[ index ]
+       ? ( path[ index ] == '/'
+           ? basenameIndex( path, index + 1, index )
+           : basenameIndex( path, index + 1, slashIndex ) )
+       : ( slashIndex + 1 );
+}
+
+#define __FILELINE__ ( { static const int32_t basenameIdx = basenameIndex( __FILE__ ); \
+                         static_assert (basenameIdx >= 0, "compile-time basename" );   \
+                         __FILE__ ":" STRINGIZE(__LINE__) + basenameIdx ; } )
+
+#define TEST_LOCATION __FILELINE__
 #define TEST_INNER_LOCATION(x) ( std::string(x) + " (" + STRINGIZE(__LINE__) + ")" ).c_str()
 
 #define TET_UNDEF 2
@@ -73,7 +86,7 @@ if ( (condition) )
 }                                                                                         \
 else                                                                                      \
 {                                                                                         \
-  fprintf(stderr, "%s Failed in %s at line %d\n", __PRETTY_FUNCTION__, __FILE__, __LINE__);    \
+  fprintf(stderr, "Test failed in %s, condition: %s\n", __FILELINE__, #condition );       \
   tet_result(TET_FAIL);                                                                   \
   throw("TET_FAIL");                                                                      \
 }
@@ -97,8 +110,9 @@ inline void DALI_TEST_EQUALS(Type value1, Type value2, const char* location)
   {
     std::ostringstream o;
     o << value1 << " == " << value2 << std::endl;
-    fprintf(stderr, "%s, checking %s", location, o.str().c_str());
+    fprintf(stderr, "Test failed in %s, checking %s", location, o.str().c_str());
     tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
   }
   else
   {
@@ -106,6 +120,13 @@ inline void DALI_TEST_EQUALS(Type value1, Type value2, const char* location)
   }
 }
 
+/**
+ * Test whether two values are equal.
+ * @param[in] value1 The first value
+ * @param[in] value2 The second value
+ */
+#define DALI_TEST_EQUAL( v1, v2 ) DALI_TEST_EQUALS( v1, v2, __FILELINE__ )
+
 template<typename Type>
 inline void DALI_TEST_EQUALS(Type value1, Type value2, float epsilon, const char* location)
 {
@@ -113,8 +134,9 @@ inline void DALI_TEST_EQUALS(Type value1, Type value2, float epsilon, const char
   {
     std::ostringstream o;
     o << value1 << " == " << value2 << std::endl;
-    fprintf(stderr, "%s, checking %s", location, o.str().c_str());
+    fprintf(stderr, "Test failed in %s, checking %s", location, o.str().c_str());
     tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
   }
   else
   {
@@ -129,8 +151,9 @@ inline void DALI_TEST_NOT_EQUALS(Type value1, Type value2, float epsilon, const
   {
     std::ostringstream o;
     o << value1 << " !=  " << value2 << std::endl;
-    fprintf(stderr, "%s, checking %s", location, o.str().c_str());
+    fprintf(stderr, "Test failed in %s, checking %s", location, o.str().c_str());
     tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
   }
   else
   {
@@ -151,13 +174,15 @@ inline void DALI_TEST_EQUALS<TimePeriod>( TimePeriod value1, TimePeriod value2,
 {
   if ((fabs(value1.durationSeconds - value2.durationSeconds) > epsilon))
   {
-    fprintf(stderr, "%s, checking durations %f == %f, epsilon %f\n", location, value1.durationSeconds, value2.durationSeconds, epsilon);
+    fprintf(stderr, "Test failed in %s, checking durations %f == %f, epsilon %f\n", location, value1.durationSeconds, value2.durationSeconds, epsilon);
     tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
   }
   else if ((fabs(value1.delaySeconds - value2.delaySeconds) > epsilon))
   {
-    fprintf(stderr, "%s, checking delays %f == %f, epsilon %f\n", location, value1.delaySeconds, value2.delaySeconds, epsilon);
+    fprintf(stderr, "Test failed in %s, checking delays %f == %f, epsilon %f\n", location, value1.delaySeconds, value2.delaySeconds, epsilon);
     tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
   }
   else
   {
@@ -232,8 +257,9 @@ inline void DALI_TEST_EQUALS<const char*>( const char* str1, const char* str2, c
 {
   if (strcmp(str1, str2))
   {
-    fprintf(stderr, "%s, checking '%s' == '%s'\n", location, str1, str2);
+    fprintf(stderr, "Test failed in %s, checking '%s' == '%s'\n", location, str1, str2);
     tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
   }
   else
   {
@@ -289,8 +315,9 @@ void DALI_TEST_GREATER( T value1, T value2, const char* location)
 {
   if (!(value1 > value2))
   {
-    std::cerr << location << ", checking " << value1 <<" > " << value2 << "\n";
+    std::cerr << "Test failed in " << location << ", checking " << value1 <<" > " << value2 << "\n";
     tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
   }
   else
   {
index 840ef0d..645d74b 100644 (file)
@@ -52,7 +52,14 @@ int RunTestCase( struct ::testcase_s& testCase )
   {
     testCase.startup();
   }
-  result = testCase.function();
+  try
+  {
+    result = testCase.function();
+  }
+  catch( const char* )
+  {
+    // just catch test fail exception, return is already set to EXIT_STATUS_TESTCASE_FAILED
+  }
   if( testCase.cleanup )
   {
     testCase.cleanup();
index 1a642dd..beba3a6 100644 (file)
@@ -986,6 +986,7 @@ int UtcDaliToolkitTextLabelColorComponents(void)
   label.SetProperty( DevelTextLabel::Property::TEXT_COLOR_ALPHA, 0.6f );
   DALI_TEST_EQUALS( label.GetProperty< float >( DevelTextLabel::Property::TEXT_COLOR_ALPHA ), 0.6f, TEST_LOCATION );
   DALI_TEST_EQUALS( label.GetProperty< Vector4 >( DevelTextLabel::Property::TEXT_COLOR_ANIMATABLE ), Vector4( 0.0f, 0.0f, 1.0f, 0.6f ), TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty< Vector4 >( TextLabel::Property::TEXT_COLOR ), Vector4( 0.0f, 0.0f, 1.0f, 0.6f ), TEST_LOCATION );
 
   END_TEST;
 }
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextureManager.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextureManager.cpp
new file mode 100644 (file)
index 0000000..89a95ba
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali/public-api/rendering/texture-set.h>
+#include <dali/public-api/rendering/texture.h>
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+
+} // namespace
+
+
+void dali_texture_manager_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_texture_manager_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliTextureManagerAddRemoveP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliTextureManager" );
+
+  std::string url;
+  std::string url2;
+  std::string url3;
+  std::string url4;
+  // scope to ensure texturesets are kept alive by texture manager
+  {
+    auto texture = Texture::New( Dali::TextureType::TEXTURE_2D, Pixel::RGBA8888, 88, 99 );
+    url = TextureManager::AddTexture( texture );
+    DALI_TEST_CHECK( url.size() > 0u );
+
+    auto textureSet = TextureSet::New();
+    textureSet.SetTexture( 0u, texture );
+    url2 = TextureManager::AddTexture( textureSet );
+    DALI_TEST_CHECK( url2.size() > 0u );
+    DALI_TEST_CHECK( url2 != url );
+
+    // add same texture again, should give new Url
+    url3 = TextureManager::AddTexture( texture );
+    DALI_TEST_CHECK( url3.size() > 0u );
+    DALI_TEST_CHECK( url3 != url );
+    DALI_TEST_CHECK( url3 != url2 );
+
+    textureSet = TextureSet::New();
+    url4 = TextureManager::AddTexture( textureSet );
+    DALI_TEST_CHECK( url4.size() > 0u );
+    DALI_TEST_CHECK( url4 != url );
+    DALI_TEST_CHECK( url4 != url2 );
+    DALI_TEST_CHECK( url4 != url3 );
+  }
+
+  auto textureSet = TextureManager::RemoveTexture( url );
+  DALI_TEST_CHECK( textureSet && "Texture needs to be non empty handle" );
+  auto texture = textureSet.GetTexture( 0u );
+  DALI_TEST_EQUAL( texture.GetWidth(), 88u );
+  DALI_TEST_EQUAL( texture.GetHeight(), 99u );
+  textureSet = TextureManager::RemoveTexture( url );
+  DALI_TEST_CHECK( !textureSet && "Texture needs to be removed from texture manager" );
+
+  textureSet = TextureManager::RemoveTexture( url2 );
+  DALI_TEST_CHECK( textureSet && "Texture needs to be non empty handle" );
+  texture = textureSet.GetTexture( 0u );
+  DALI_TEST_EQUAL( texture.GetWidth(), 88u );
+  DALI_TEST_EQUAL( texture.GetHeight(), 99u );
+  textureSet = TextureManager::RemoveTexture( url2 );
+  DALI_TEST_CHECK( !textureSet && "Texture needs to be removed from texture manager" );
+
+  textureSet = TextureManager::RemoveTexture( url3 );
+  DALI_TEST_CHECK( textureSet && "Texture needs to be non empty handle" );
+  texture = textureSet.GetTexture( 0u );
+  DALI_TEST_EQUAL( texture.GetWidth(), 88u );
+  DALI_TEST_EQUAL( texture.GetHeight(), 99u );
+  textureSet = TextureManager::RemoveTexture( url3 );
+  DALI_TEST_CHECK( !textureSet && "Texture needs to be removed from texture manager" );
+
+  textureSet = TextureManager::RemoveTexture( url4 );
+  DALI_TEST_CHECK( textureSet && "Texture needs to be non empty handle" );
+  textureSet = TextureManager::RemoveTexture( url4 );
+  DALI_TEST_CHECK( !textureSet && "Texture needs to be removed from texture manager" );
+
+  END_TEST;
+}
+
+int UtcDaliTextureManagerAddN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliTextureManager" );
+
+  // empty texture is ok, though pointless from app point of view
+  TextureSet empty;
+  std::string url = TextureManager::AddTexture( empty );
+  DALI_TEST_CHECK( url.size() > 0u );
+
+  END_TEST;
+}
+
+int UtcDaliTextureManagerRemoveN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliTextureManager" );
+
+  // removing empty texture returns empty handle
+  auto texture = TextureManager::RemoveTexture( "" );
+  DALI_TEST_CHECK( !texture && "Texture should not be found" );
+
+  // removing empty texture returns empty handle
+  texture = TextureManager::RemoveTexture( "dali://" );
+  DALI_TEST_CHECK( !texture && "Texture should not be found" );
+
+  // empty texture is ok, though pointless from app point of view
+  TextureSet empty;
+  std::string url = TextureManager::AddTexture( empty );
+  DALI_TEST_CHECK( url.size() > 0u );
+  // removing texture with wrong URL returns empty handle
+  texture = TextureManager::RemoveTexture( "dali://" );
+  DALI_TEST_CHECK( !texture && "Texture should not be found" );
+
+  // removing ftp texture returns empty handle
+  texture = TextureManager::RemoveTexture( "ftp://foobar" );
+  DALI_TEST_CHECK( !texture && "Texture should not be found" );
+
+  // add a texture
+  url = TextureManager::AddTexture( texture );
+  texture = TextureManager::RemoveTexture( url + "foo" );
+  DALI_TEST_CHECK( !texture && "Texture should not be found" );
+
+  END_TEST;
+}
+
+
+
index 3df2c08..1649112 100755 (executable)
@@ -58,7 +58,7 @@ rename_cov_data:
        @rm -f $(COVERAGE_DIR)/*
        @cp dali-toolkit/.libs/*.gcda dali-toolkit/.libs/*.gcno  $(COVERAGE_DIR)
        @for i in `find $(COVERAGE_DIR) -name "libdali_toolkit*_la-*.gcda" -o -name "libdali_toolkit*_la-*.gcno"` ;\
-               do mv $$i `echo $$i | sed s/libdali_toolkit*_la-//` ; echo $$i ; done
+               do dest=`echo $$i | sed s/libdali_.*_la-//` ; mv $$i $$dest ; echo $$i ; done
 
 cov_data: rename_cov_data
        @cd $(COVERAGE_DIR) ; lcov $(LCOV_OPTS) --base-directory . --directory . -c -o dali.info
index 7f4308b..5cf6797 100644 (file)
@@ -30,6 +30,7 @@ devel_api_src_files = \
   $(devel_api_src_dir)/image-loader/async-image-loader-devel.cpp \
   $(devel_api_src_dir)/image-loader/atlas-upload-observer.cpp \
   $(devel_api_src_dir)/image-loader/image-atlas.cpp \
+  $(devel_api_src_dir)/image-loader/texture-manager.cpp \
   $(devel_api_src_dir)/scripting/script.cpp \
   $(devel_api_src_dir)/styling/style-manager-devel.cpp \
   $(devel_api_src_dir)/transition-effects/cube-transition-cross-effect.cpp \
diff --git a/dali-toolkit/devel-api/image-loader/texture-manager.cpp b/dali-toolkit/devel-api/image-loader/texture-manager.cpp
new file mode 100644 (file)
index 0000000..d46d2b4
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace TextureManager
+{
+
+std::string AddTexture( Texture& texture )
+{
+  TextureSet set = TextureSet::New();
+  set.SetTexture( 0u, texture );
+  return AddTexture( set );
+}
+
+std::string AddTexture( TextureSet& textureSet )
+{
+  auto visualFactory = Toolkit::VisualFactory::Get();
+  auto& textureMgr = GetImplementation( visualFactory ).GetTextureManager();
+  return textureMgr.AddExternalTexture( textureSet );
+}
+
+TextureSet RemoveTexture( const std::string& textureUrl )
+{
+  auto visualFactory = Toolkit::VisualFactory::Get();
+  auto& textureMgr = GetImplementation( visualFactory ).GetTextureManager();
+  return textureMgr.RemoveExternalTexture( textureUrl );
+}
+
+} // TextureManager
+
+} // Toolkit
+
+} // Dali
diff --git a/dali-toolkit/devel-api/image-loader/texture-manager.h b/dali-toolkit/devel-api/image-loader/texture-manager.h
new file mode 100644 (file)
index 0000000..b88eab9
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef DALI_TOOLKIT_DEVEL_API_TEXTURE_MANAGER_H
+#define DALI_TOOLKIT_DEVEL_API_TEXTURE_MANAGER_H
+
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/rendering/texture-set.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * API to interface with the toolkit texture manager
+ * Allows developers to add Textures through TextureSets to toolkit so that visuals can use them to render
+ */
+namespace TextureManager
+{
+
+/**
+ * @brief Add a Texture to texture manager
+ * Toolkit keeps the Texture handle until RemoveTexture is called.
+ * @note this method does not check for duplicates,
+ *       if same Texture is added multiple times, a different URL is returned each time
+ * @param[in] texture the Texture to add
+ * @return the Url string representing this texture
+ */
+DALI_IMPORT_API std::string AddTexture( Texture& texture );
+
+/**
+ * @brief Add a TextureSet to texture manager
+ * Toolkit keeps the TextureSet handle until RemoveTexture is called.
+ * @note this method does not check for duplicates,
+ *       if same TextureSet is added multiple times, a different URL is returned each time
+ * @param[in] textureSet the TextureSet to add
+ * @return the Url string representing this texture
+ */
+DALI_IMPORT_API std::string AddTexture( TextureSet& textureSet );
+
+/**
+ * @brief Removes a TextureSet from toolkit
+ * @note TextureSet may still be used by visuals and kept alive by them
+ * @param[in] textureUrl to remove
+ * @return the handle to the TextureSet or empty handle in case TextureSet is not found
+ */
+DALI_IMPORT_API TextureSet RemoveTexture( const std::string& textureUrl );
+
+}
+
+} // Toolkit
+
+} // Dali
+
+#endif // DALI_TOOLKIT_DEVEL_API_TEXTURE_MANAGER_H
index 10adcbc..4286c38 100644 (file)
@@ -88,6 +88,18 @@ enum
    * @details name "enableMarkup", type BOOLEAN
    */
   ENABLE_MARKUP,
+
+  /**
+   * @brief The shadow parameters.
+   * @details name "shadow", type MAP.
+   */
+  SHADOW,
+
+  /**
+   * @brief The default underline parameters.
+   * @details name "underline", type MAP.
+   */
+  UNDERLINE,
 };
 
 } // namespace Property
index db99cc4..e871db3 100644 (file)
 #include <dali-toolkit/internal/text/text-definitions.h>
 #include <dali-toolkit/internal/styling/style-manager-impl.h>
 
+#include <dali-toolkit/devel-api/align-enums.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+#include <dali-toolkit/devel-api/visuals/text-visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+
 using namespace Dali::Toolkit::Text;
 
 namespace Dali
@@ -97,7 +104,7 @@ BaseHandle Create()
 // Setup properties, signals and actions using the type-registry.
 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextLabel, Toolkit::Control, Create );
 
-DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "renderingBackend",          INTEGER, RENDERING_BACKEND      )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "renderingBackend",          INTEGER, RENDERING_BACKEND      ) // Deprecated property
 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "text",                      STRING,  TEXT                   )
 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "fontFamily",                STRING,  FONT_FAMILY            )
 DALI_PROPERTY_REGISTRATION( Toolkit, TextLabel, "fontStyle",                 MAP,     FONT_STYLE             )
@@ -127,7 +134,7 @@ DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "autoScrollLoopDelay", FLO
 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "autoScrollStopMode",  STRING,  AUTO_SCROLL_STOP_MODE  )
 DALI_DEVEL_PROPERTY_REGISTRATION_READ_ONLY( Toolkit, TextLabel, "lineCount", INTEGER, LINE_COUNT             )
 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "lineWrapMode",        STRING,  LINE_WRAP_MODE         )
-DALI_DEVEL_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( Toolkit, TextLabel, "textColorAnimatable", Color::WHITE, TEXT_COLOR_ANIMATABLE )
+DALI_DEVEL_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( Toolkit, TextLabel, "textColorAnimatable", Color::BLACK, TEXT_COLOR_ANIMATABLE )
 DALI_DEVEL_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, TextLabel, "textColorRed",   TEXT_COLOR_RED,   TEXT_COLOR_ANIMATABLE, 0)
 DALI_DEVEL_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, TextLabel, "textColorGreen", TEXT_COLOR_GREEN, TEXT_COLOR_ANIMATABLE, 1)
 DALI_DEVEL_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, TextLabel, "textColorBlue",  TEXT_COLOR_BLUE,  TEXT_COLOR_ANIMATABLE, 2)
@@ -162,6 +169,8 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
     {
       case Toolkit::TextLabel::Property::RENDERING_BACKEND:
       {
+        DALI_LOG_WARNING("[%s] Using deprecated Property TextLabel::Property::RENDERING_BACKEND which is no longer supported and will be ignored\n", __FUNCTION__);
+
         int backend = value.Get< int >();
 
 #ifndef ENABLE_VECTOR_BASED_TEXT_RENDERING
@@ -173,7 +182,7 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
         if( impl.mRenderingBackend != backend )
         {
           impl.mRenderingBackend = backend;
-          impl.mRenderer.Reset();
+          impl.mTextUpdateNeeded = true;
 
           if( impl.mController )
           {
@@ -262,7 +271,8 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
 
       case Toolkit::TextLabel::Property::TEXT_COLOR:
       {
-        SetProperty( object, DevelTextLabel::Property::TEXT_COLOR_ANIMATABLE, value );
+        label.SetProperty( DevelTextLabel::Property::TEXT_COLOR_ANIMATABLE, value );
+        impl.mTextUpdateNeeded = true;
         break;
       }
 
@@ -274,7 +284,7 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
           if ( impl.mController->GetShadowOffset() != shadowOffset )
           {
             impl.mController->SetShadowOffset( shadowOffset );
-            impl.mRenderer.Reset();
+            impl.mTextUpdateNeeded = true;
           }
         }
         break;
@@ -287,7 +297,7 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
           if ( impl.mController->GetShadowColor() != shadowColor )
           {
             impl.mController->SetShadowColor( shadowColor );
-            impl.mRenderer.Reset();
+            impl.mTextUpdateNeeded = true;
           }
         }
         break;
@@ -300,7 +310,7 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
           if ( impl.mController->GetUnderlineColor() != color )
           {
             impl.mController->SetUnderlineColor( color );
-            impl.mRenderer.Reset();
+            impl.mTextUpdateNeeded = true;
           }
         }
         break;
@@ -313,7 +323,7 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
           if ( impl.mController->IsUnderlineEnabled() != enabled )
           {
             impl.mController->SetUnderlineEnabled( enabled );
-            impl.mRenderer.Reset();
+            impl.mTextUpdateNeeded = true;
           }
         }
         break;
@@ -327,7 +337,7 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
           if( fabsf( impl.mController->GetUnderlineHeight() - height ) > Math::MACHINE_EPSILON_1000 )
           {
             impl.mController->SetUnderlineHeight( height );
-            impl.mRenderer.Reset();
+            impl.mTextUpdateNeeded = true;
           }
         }
         break;
@@ -425,7 +435,7 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
         {
           const float lineSpacing = value.Get<float>();
           impl.mController->SetDefaultLineSpacing( lineSpacing );
-          impl.mRenderer.Reset();
+          impl.mTextUpdateNeeded = true;
         }
         break;
       }
@@ -434,7 +444,7 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
         const bool update = SetUnderlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
         if( update )
         {
-          impl.mRenderer.Reset();
+          impl.mTextUpdateNeeded = true;
         }
         break;
       }
@@ -443,7 +453,7 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
         const bool update = SetShadowProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
         if( update )
         {
-          impl.mRenderer.Reset();
+          impl.mTextUpdateNeeded = true;
         }
         break;
       }
@@ -452,7 +462,7 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
         const bool update = SetEmbossProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
         if( update )
         {
-          impl.mRenderer.Reset();
+          impl.mTextUpdateNeeded = true;
         }
         break;
       }
@@ -461,7 +471,7 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
         const bool update = SetOutlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
         if( update )
         {
-          impl.mRenderer.Reset();
+          impl.mTextUpdateNeeded = true;
         }
         break;
       }
@@ -522,6 +532,8 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde
     {
       case Toolkit::TextLabel::Property::RENDERING_BACKEND:
       {
+        DALI_LOG_WARNING("[%s] Using deprecated Property TextLabel::Property::RENDERING_BACKEND which is no longer supported and will be ignored\n", __FUNCTION__);
+
         value = impl.mRenderingBackend;
         break;
       }
@@ -594,10 +606,7 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde
       }
       case Toolkit::TextLabel::Property::TEXT_COLOR:
       {
-        if( impl.mController )
-        {
-          value = impl.mController->GetDefaultColor();
-        }
+        value = label.GetProperty( Toolkit::DevelTextLabel::Property::TEXT_COLOR_ANIMATABLE );
         break;
       }
       case Toolkit::TextLabel::Property::SHADOW_OFFSET:
@@ -783,11 +792,19 @@ void TextLabel::OnInitialize()
 {
   Actor self = Self();
 
-  mController = Text::Controller::New( this );
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, Toolkit::DevelVisual::TEXT );
 
-  // When using the vector-based rendering, the size of the GLyphs are different
-  TextAbstraction::GlyphType glyphType = (Text::RENDERING_VECTOR_BASED == mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH;
-  mController->SetGlyphType( glyphType );
+  mVisual =  Toolkit::VisualFactory::Get().CreateVisual( propertyMap );
+  DevelControl::RegisterVisual( *this, Toolkit::TextLabel::Property::TEXT, mVisual  );
+
+  TextVisual::SetAnimatableTextColorProperty( mVisual, Toolkit::DevelTextLabel::Property::TEXT_COLOR_ANIMATABLE );
+
+  mController = TextVisual::GetController(mVisual);
+  if( mController )
+  {
+    mController->SetControlInterface(this);
+  }
 
   // Use height-for-width negotiation by default
   self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
@@ -798,8 +815,6 @@ void TextLabel::OnInitialize()
 
   Layout::Engine& engine = mController->GetLayoutEngine();
   engine.SetCursorWidth( 0u ); // Do not layout space for the cursor.
-
-  self.OnStageSignal().Connect( this, &TextLabel::OnStageConnect );
 }
 
 void TextLabel::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
@@ -852,14 +867,13 @@ void TextLabel::OnPropertySet( Property::Index index, Property::Value propertyVa
 
   switch ( index )
   {
-    case Toolkit::TextLabel::Property::TEXT_COLOR:
     case Toolkit::DevelTextLabel::Property::TEXT_COLOR_ANIMATABLE:
     {
       const Vector4& textColor = propertyValue.Get< Vector4 >();
       if( mController->GetDefaultColor() != textColor )
       {
          mController->SetDefaultColor( textColor );
-         mRenderer.Reset();
+         mTextUpdateNeeded = true;
       }
       break;
     }
@@ -879,76 +893,50 @@ void TextLabel::OnRelayout( const Vector2& size, RelayoutContainer& container )
   Self().GetPadding( padding );
   Vector2 contentSize( size.x - ( padding.left + padding.right ), size.y - ( padding.top + padding.bottom ) );
 
-
   const Text::Controller::UpdateTextType updateTextType = mController->Relayout( contentSize );
 
-  if( ( Text::Controller::NONE_UPDATED != ( Text::Controller::MODEL_UPDATED & updateTextType ) ) ||
-      !mRenderer )
+  if( ( Text::Controller::NONE_UPDATED != ( Text::Controller::MODEL_UPDATED & updateTextType ) )
+     || mTextUpdateNeeded )
   {
-    if( !mRenderer )
-    {
-      mRenderer = Text::Backend::Get().NewRenderer( mRenderingBackend );
-    }
-    RenderText();
-  }
-}
-
-void TextLabel::RequestTextRelayout()
-{
-  RelayoutRequest();
-}
+    DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::OnRelayout IsAutoScrollEnabled[%s] [%p]\n", ( mController->IsAutoScrollEnabled())?"true":"false", this );
 
-void TextLabel::RenderText()
-{
-  DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::RenderText IsAutoScrollEnabled[%s] [%p]\n", ( mController->IsAutoScrollEnabled())?"true":"false", this );
+    // Update the visual
+    TextVisual::EnableRendererUpdate( mVisual );
 
-  Actor self = Self();
-  Actor renderableActor;
+    Padding padding;
+    Self().GetPadding( padding );
 
-  float alignmentOffset = 0.f;
-  if( mRenderer )
-  {
-
-    Dali::Toolkit::TextLabel handle = Dali::Toolkit::TextLabel( GetOwner() );
-
-    renderableActor = mRenderer->Render( mController->GetView(),
-                                         handle,
-                                         Toolkit::DevelTextLabel::Property::TEXT_COLOR_ANIMATABLE,
-                                         alignmentOffset,
-                                         DepthIndex::CONTENT );
-  }
-
-  if( renderableActor != mRenderableActor )
-  {
-    UnparentAndReset( mRenderableActor );
-
-    if( renderableActor )
-    {
-      const Vector2& scrollOffset = mController->GetTextModel()->GetScrollPosition();
-      Padding padding;
-      self.GetPadding( padding );
-      renderableActor.SetPosition( scrollOffset.x + alignmentOffset + padding.left, scrollOffset.y + padding.top );
-
-      self.Add( renderableActor );
-    }
-    mRenderableActor = renderableActor;
+    Property::Map visualTransform;
+    visualTransform.Add( Toolkit::DevelVisual::Transform::Property::SIZE, contentSize )
+                   .Add( Toolkit::DevelVisual::Transform::Property::SIZE_POLICY, Vector2( DevelVisual::Transform::Policy::ABSOLUTE, DevelVisual::Transform::Policy::ABSOLUTE ) )
+                   .Add( Toolkit::DevelVisual::Transform::Property::OFFSET, Vector2(padding.left, padding.top) )
+                   .Add( Toolkit::DevelVisual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::DevelVisual::Transform::Policy::ABSOLUTE, Toolkit::DevelVisual::Transform::Policy::ABSOLUTE ) )
+                   .Add( Toolkit::DevelVisual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
+                   .Add( Toolkit::DevelVisual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN );
+    mVisual.SetTransformAndSize( visualTransform, size );
 
     if ( mController->IsAutoScrollEnabled() )
     {
       SetUpAutoScrolling();
     }
+
+    mTextUpdateNeeded = false;
   }
 }
 
+void TextLabel::RequestTextRelayout()
+{
+  RelayoutRequest();
+}
+
 void TextLabel::SetUpAutoScrolling()
 {
   const Size& controlSize = mController->GetView().GetControlSize();
-  const Size offScreenSize = GetNaturalSize().GetVectorXY(); // As relayout of text may not be done at this point natural size is used to get size. Single line scrolling only.
-  const float alignmentOffset = mController->GetAutoScrollLineAlignment();
+  const Size textNaturalSize = GetNaturalSize().GetVectorXY(); // As relayout of text may not be done at this point natural size is used to get size. Single line scrolling only.
   const Text::CharacterDirection direction = mController->GetAutoScrollDirection();
 
-  DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::SetUpAutoScrolling alignmentOffset[%f] offScreenSize[%f,%f] controlSize[%f,%f]\n",
-                 alignmentOffset, offScreenSize.x,offScreenSize.y , controlSize.x,controlSize.y );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::SetUpAutoScrolling textNaturalSize[%f,%f] controlSize[%f,%f]\n",
+                 textNaturalSize.x,textNaturalSize.y , controlSize.x,controlSize.y );
 
   if ( !mTextScroller )
   {
@@ -957,23 +945,27 @@ void TextLabel::SetUpAutoScrolling()
     // If speed, loopCount or gap not set via property system then will need to create a TextScroller with defaults
     mTextScroller = Text::TextScroller::New( *this );
   }
-  mTextScroller->SetParameters( mRenderableActor, controlSize, offScreenSize, direction, alignmentOffset, mController->GetHorizontalAlignment() );
-
-  Actor self = Self();
-  self.Add( mTextScroller->GetScrollingText() );
-  self.Add( mTextScroller->GetSourceCamera() );
-}
 
-void TextLabel::OnStageConnect( Dali::Actor actor )
-{
-  if ( mHasBeenStaged )
-  {
-    RenderText();
-  }
-  else
-  {
-    mHasBeenStaged = true;
-  }
+  // Create a texture of the text for scrolling
+  Text::TypesetterPtr typesetter = Text::Typesetter::New( mController->GetTextModel() );
+  PixelData data = typesetter->Render( textNaturalSize, Text::Typesetter::RENDER_TEXT_AND_STYLES, true, Pixel::RGBA8888 ); // ignore the horizontal alignment
+  Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
+                                  data.GetPixelFormat(),
+                                  data.GetWidth(),
+                                  data.GetHeight() );
+  texture.Upload( data );
+
+  TextureSet textureSet = TextureSet::New();
+  textureSet.SetTexture( 0u, texture );
+
+  // Filter mode needs to be set to linear to produce better quality while scaling.
+  Sampler sampler = Sampler::New();
+  sampler.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR );
+  textureSet.SetSampler( 0u, sampler );
+
+  // Set parameters for scrolling
+  Renderer renderer = static_cast<Internal::Visual::Base&>( GetImplementation( mVisual ) ).GetRenderer();
+  mTextScroller->SetParameters( Self(), renderer, textureSet, controlSize, textNaturalSize, direction, mController->GetHorizontalAlignment(), mController->GetVerticalAlignment() );
 }
 
 void TextLabel::ScrollingFinished()
@@ -988,7 +980,7 @@ void TextLabel::ScrollingFinished()
 TextLabel::TextLabel()
 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
   mRenderingBackend( DEFAULT_RENDERING_BACKEND ),
-  mHasBeenStaged( false )
+  mTextUpdateNeeded( false )
 {
 }
 
index f15acbf..85e94ab 100644 (file)
@@ -18,6 +18,9 @@
  *
  */
 
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/property-map.h>
+
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/controls/control-impl.h>
 #include <dali-toolkit/public-api/controls/text-controls/text-label.h>
@@ -26,6 +29,8 @@
 #include <dali-toolkit/internal/text/text-scroller-interface.h>
 #include <dali-toolkit/internal/text/rendering/text-renderer.h>
 #include <dali-toolkit/internal/text/text-scroller.h>
+#include <dali-toolkit/internal/visuals/text/text-visual.h>
+
 
 namespace Dali
 {
@@ -132,14 +137,6 @@ private:
   TextLabel(const TextLabel&);
   TextLabel& operator=(const TextLabel& rhs);
 
-  // Connection needed to re-render text, when a Text Label returns to the stage
-  void OnStageConnect( Dali::Actor actor );
-
-  /**
-   * @brief Render view, create and attach actor(s) to this Text Label
-   */
-  void RenderText();
-
   /**
    * @brief Set up Autoscrolling
    */
@@ -148,11 +145,12 @@ private:
 private: // Data
 
   Text::ControllerPtr mController;
-  Text::RendererPtr mRenderer;
   Text::TextScrollerPtr mTextScroller;
-  Actor mRenderableActor;
+
+  Toolkit::Visual::Base mVisual;
+
   int mRenderingBackend;
-  bool mHasBeenStaged:1;
+  bool mTextUpdateNeeded:1;
 };
 
 } // namespace Internal
index b09de6b..2fdb70b 100644 (file)
@@ -620,7 +620,11 @@ void VideoView::SetWindowSurfaceTarget()
     mVideoPlayer.Play();
     mVideoPlayer.Pause();
   }
-  mVideoPlayer.SetPlayPosition( curPos );
+
+  if( curPos > 0 )
+  {
+    mVideoPlayer.SetPlayPosition( curPos );
+  }
 
   // For underlay rendering mode, video display area have to be transparent.
   Geometry geometry = VisualFactoryCache::CreateQuadGeometry();
@@ -660,7 +664,10 @@ void VideoView::SetNativeImageTarget()
     mVideoPlayer.Play();
     mVideoPlayer.Pause();
   }
-  mVideoPlayer.SetPlayPosition( curPos );
+  if( curPos > 0 )
+  {
+    mVideoPlayer.SetPlayPosition( curPos );
+  }
 }
 
 void VideoView::UpdateDisplayArea()
index 9b6809f..77df72f 100644 (file)
@@ -31,7 +31,7 @@ toolkit_src_files = \
    $(toolkit_src_dir)/visuals/svg/svg-visual.cpp \
    $(toolkit_src_dir)/visuals/text/text-visual.cpp \
    $(toolkit_src_dir)/visuals/transition-data-impl.cpp \
-   $(toolkit_src_dir)/visuals/texture-manager.cpp \
+   $(toolkit_src_dir)/visuals/texture-manager-impl.cpp \
    $(toolkit_src_dir)/visuals/texture-upload-observer.cpp \
    $(toolkit_src_dir)/visuals/visual-base-data-impl.cpp \
    $(toolkit_src_dir)/visuals/visual-base-impl.cpp \
index c1b4a91..7e0a181 100644 (file)
@@ -44,7 +44,7 @@ LoadingTask::LoadingTask( uint32_t id, const VisualUrl& url, ImageDimensions dim
 
 void LoadingTask::Load()
 {
-  if( url.IsLocal() )
+  if( url.IsLocalResource() )
   {
     pixelBuffer = Dali::LoadImageFromFile( url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection );
   }
index 78aba49..66bb797 100644 (file)
@@ -21,6 +21,7 @@
 // EXTERNAL INCLUDES
 #include <dali/devel-api/text-abstraction/font-client.h>
 #include <memory.h>
+#include <dali/public-api/common/constants.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/rendering/view-model.h>
@@ -42,7 +43,7 @@ namespace
  */
 struct GlyphData
 {
-  uint32_t*                                    bitmapBuffer;     ///< The buffer of the whole bitmap. The format is RGBA8888.
+  Devel::PixelBuffer                           bitmapBuffer;     ///< The buffer of the whole bitmap. The format is RGBA8888.
   Vector2*                                     position;         ///< The position of the glyph.
   TextAbstraction::FontClient::GlyphBufferData glyphBitmap;      ///< The glyph's bitmap.
   unsigned int                                 width;            ///< The bitmap's width.
@@ -57,10 +58,14 @@ struct GlyphData
  * @param[in] data Struct which contains the glyph's data and the bitmap's data.
  * @param[in] position The position of the glyph.
  * @param[in] color The color of the glyph.
+ * @param[in] style The style of the text.
+ * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
  */
-void TypesetGlyph( const GlyphData& data,
+void TypesetGlyph( GlyphData& data,
                    const Vector2* const position,
-                   const Vector4* const color )
+                   const Vector4* const color,
+                   Typesetter::Style style,
+                   Pixel::Format pixelFormat )
 {
   if( ( 0u == data.glyphBitmap.width ) || ( 0u == data.glyphBitmap.height ) )
   {
@@ -71,71 +76,179 @@ void TypesetGlyph( const GlyphData& data,
   const int widthMinusOne = static_cast<int>( data.width - 1u );
   const int heightMinusOne = static_cast<int>( data.height - 1u );
 
-  // Whether the given glyph is a color one.
-  const bool isColorGlyph = Pixel::BGRA8888 == data.glyphBitmap.format;
+  if ( Pixel::RGBA8888 == pixelFormat )
+  {
+    // Whether the given glyph is a color one.
+    const bool isColorGlyph = Pixel::BGRA8888 == data.glyphBitmap.format;
 
-  // Pointer to the color glyph if there is one.
-  const uint32_t* const colorGlyphBuffer = isColorGlyph ? reinterpret_cast<uint32_t*>( data.glyphBitmap.buffer ) : NULL;
+    // Pointer to the color glyph if there is one.
+    const uint32_t* const colorGlyphBuffer = isColorGlyph ? reinterpret_cast<uint32_t*>( data.glyphBitmap.buffer ) : NULL;
 
-  // Pack the given color into a 32bit buffer. The alpha channel will be updated later for each pixel.
-  // The format is RGBA8888.
-  uint32_t packedColor = 0u;
-  uint8_t* packedColorBuffer = reinterpret_cast<uint8_t*>( &packedColor );
-  *( packedColorBuffer + 2 ) = static_cast<uint8_t>( color->b * 255.f );
-  *( packedColorBuffer + 1 ) = static_cast<uint8_t>( color->g * 255.f );
-    *packedColorBuffer       = static_cast<uint8_t>( color->r * 255.f );
+    // Pack the given color into a 32bit buffer. The alpha channel will be updated later for each pixel.
+    // The format is RGBA8888.
+    uint32_t packedColor = 0u;
+    uint8_t* packedColorBuffer = reinterpret_cast<uint8_t*>( &packedColor );
+    *( packedColorBuffer + 2 ) = static_cast<uint8_t>( color->b * 255.f );
+    *( packedColorBuffer + 1 ) = static_cast<uint8_t>( color->g * 255.f );
+      *packedColorBuffer       = static_cast<uint8_t>( color->r * 255.f );
 
-  // Initial vertical offset.
-  const int yOffset = data.verticalOffset + position->y;
+    // Initial vertical offset.
+    const int yOffset = data.verticalOffset + position->y;
 
-  // Traverse the pixels of the glyph line per line.
-  for( int lineIndex = 0, glyphHeight = static_cast<int>( data.glyphBitmap.height ); lineIndex < glyphHeight; ++lineIndex )
-  {
-    const int yOffsetIndex = yOffset + lineIndex;
-    if( ( 0 > yOffsetIndex ) || ( yOffsetIndex > heightMinusOne ) )
+    // Traverse the pixels of the glyph line per line.
+    for( int lineIndex = 0, glyphHeight = static_cast<int>( data.glyphBitmap.height ); lineIndex < glyphHeight; ++lineIndex )
     {
-      // Do not write out of bounds.
-      break;
+      const int yOffsetIndex = yOffset + lineIndex;
+      if( ( 0 > yOffsetIndex ) || ( yOffsetIndex > heightMinusOne ) )
+      {
+        // Do not write out of bounds.
+        break;
+      }
+
+      const int verticalOffset = yOffsetIndex * data.width;
+      const int xOffset = data.horizontalOffset + position->x;
+      const int glyphBufferOffset = lineIndex * static_cast<int>( data.glyphBitmap.width );
+      for( int index = 0, glyphWidth = static_cast<int>( data.glyphBitmap.width ); index < glyphWidth; ++index )
+      {
+        const int xOffsetIndex = xOffset + index;
+        if( ( 0 > xOffsetIndex ) || ( xOffsetIndex > widthMinusOne ) )
+        {
+          // Don't write out of bounds.
+          break;
+        }
+
+        uint32_t* bitmapBuffer = reinterpret_cast< uint32_t* >( data.bitmapBuffer.GetBuffer() );
+
+        if( isColorGlyph )
+        {
+          // Retrieves the color from the color glyph. The format is BGRA8888.
+          uint32_t packedColorGlyph = *( colorGlyphBuffer + glyphBufferOffset + index );
+          uint8_t* packedColorGlyphBuffer = reinterpret_cast<uint8_t*>( &packedColorGlyph );
+
+          if( Typesetter::STYLE_SHADOW == style )
+          {
+            // The shadow of color glyph needs to have the shadow color.
+            *( packedColorGlyphBuffer + 2 ) = static_cast<uint8_t>( color->b * 255.f );
+            *( packedColorGlyphBuffer + 1 ) = static_cast<uint8_t>( color->g * 255.f );
+              *packedColorGlyphBuffer       = static_cast<uint8_t>( color->r * 255.f );
+          }
+          else
+          {
+            std::swap( *packedColorGlyphBuffer, *( packedColorGlyphBuffer + 2u ) ); // Swap B and R.
+          }
+
+          // Update the alpha channel.
+          if( Typesetter::STYLE_MASK == style )
+          {
+            // Create an alpha mask for color glyph.
+            *( packedColorGlyphBuffer + 3u ) = 0u;
+          }
+          else
+          {
+            *( packedColorGlyphBuffer + 3u ) = static_cast<uint8_t>( color->a * static_cast<float>( *( packedColorGlyphBuffer + 3u ) ) );
+          }
+
+          // Set the color into the final pixel buffer.
+          *( bitmapBuffer + verticalOffset + xOffsetIndex ) = packedColorGlyph;
+        }
+        else
+        {
+          // Update the alpha channel.
+          const uint8_t alpha = *( data.glyphBitmap.buffer + glyphBufferOffset + index );
+
+          // Copy non-transparent pixels only
+          if ( alpha > 0u )
+          {
+            // Check alpha of overlapped pixels
+            uint32_t& currentColor = *( bitmapBuffer + verticalOffset + xOffsetIndex );
+            uint8_t* packedCurrentColorBuffer = reinterpret_cast<uint8_t*>( &currentColor );
+
+            uint8_t currentAlpha = *( packedCurrentColorBuffer + 3u );
+            uint8_t newAlpha = static_cast<uint8_t>( color->a * static_cast<float>( alpha ) );
+
+            // For any pixel overlapped with the pixel in previous glyphs, make sure we don't
+            // overwrite a previous bigger alpha with a smaller alpha (in order to avoid
+            // semi-transparent gaps between joint glyphs with overlapped pixels, which could
+            // happen, for example, in the RTL text when we copy glyphs from right to left).
+            *( packedColorBuffer + 3u ) = std::max( currentAlpha, newAlpha );
+
+            // Set the color into the final pixel buffer.
+            currentColor = packedColor;
+          }
+        }
+      }
     }
+  }
+  else
+  {
+    // Initial vertical offset.
+    const int yOffset = data.verticalOffset + position->y;
 
-    const int verticalOffset = yOffsetIndex * data.width;
-    const int xOffset = data.horizontalOffset + position->x;
-    const int glyphBufferOffset = lineIndex * static_cast<int>( data.glyphBitmap.width );
-    for( int index = 0, glyphWidth = static_cast<int>( data.glyphBitmap.width ); index < glyphWidth; ++index )
+    // Traverse the pixels of the glyph line per line.
+    for( int lineIndex = 0, glyphHeight = static_cast<int>( data.glyphBitmap.height ); lineIndex < glyphHeight; ++lineIndex )
     {
-      const int xOffsetIndex = xOffset + index;
-      if( ( 0 > xOffsetIndex ) || ( xOffsetIndex > widthMinusOne ) )
+      const int yOffsetIndex = yOffset + lineIndex;
+      if( ( 0 > yOffsetIndex ) || ( yOffsetIndex > heightMinusOne ) )
       {
-        // Don't write out of bounds.
+        // Do not write out of bounds.
         break;
       }
 
-      if( isColorGlyph )
+      const int verticalOffset = yOffsetIndex * data.width;
+      const int xOffset = data.horizontalOffset + position->x;
+      const int glyphBufferOffset = lineIndex * static_cast<int>( data.glyphBitmap.width );
+      for( int index = 0, glyphWidth = static_cast<int>( data.glyphBitmap.width ); index < glyphWidth; ++index )
       {
-        // Retrieves the color from the glyph. The format is BGRA8888.
-        uint32_t packedColorGlyph = *( colorGlyphBuffer + glyphBufferOffset + index );
+        const int xOffsetIndex = xOffset + index;
+        if( ( 0 > xOffsetIndex ) || ( xOffsetIndex > widthMinusOne ) )
+        {
+          // Don't write out of bounds.
+          break;
+        }
 
-        // Update the alpha channel.
-        uint8_t* packedColorGlyphBuffer = reinterpret_cast<uint8_t*>( &packedColorGlyph );
-        std::swap( *packedColorGlyphBuffer, *( packedColorGlyphBuffer + 2u ) ); // Swap B and R.
-        *( packedColorGlyphBuffer + 3u ) = static_cast<uint8_t>( color->a * static_cast<float>( *( packedColorGlyphBuffer + 3u ) ) );
+        uint8_t* bitmapBuffer = reinterpret_cast< uint8_t* >( data.bitmapBuffer.GetBuffer() );
 
-        // Set the color into the final pixel buffer.
-        *( data.bitmapBuffer + verticalOffset + xOffsetIndex ) = packedColorGlyph;
-      }
-      else
-      {
         // Update the alpha channel.
         const uint8_t alpha = *( data.glyphBitmap.buffer + glyphBufferOffset + index );
-        *( packedColorBuffer + 3u ) = static_cast<uint8_t>( color->a * static_cast<float>( alpha ) );
 
-        // Set the color into the final pixel buffer.
-        *( data.bitmapBuffer + verticalOffset + xOffsetIndex ) = packedColor;
+        // Copy non-transparent pixels only
+        if ( alpha > 0u )
+        {
+          // Check alpha of overlapped pixels
+          uint8_t& currentAlpha = *( bitmapBuffer + verticalOffset + xOffsetIndex );
+          uint8_t newAlpha = static_cast<uint8_t>( color->a * static_cast<float>( alpha ) );
+//          printf("y: %d, x: %d: alpha: %u, currentAlpha: %u, newAlpha: %u, a: %u\n", yOffsetIndex, xOffsetIndex, alpha, currentAlpha, newAlpha, std::max( currentAlpha, newAlpha ) );
+
+          // For any pixel overlapped with the pixel in previous glyphs, make sure we don't
+          // overwrite a previous bigger alpha with a smaller alpha (in order to avoid
+          // semi-transparent gaps between joint glyphs with overlapped pixels, which could
+          // happen, for example, in the RTL text when we copy glyphs from right to left).
+          *( bitmapBuffer + verticalOffset + xOffsetIndex ) = std::max( currentAlpha, newAlpha );
+        }
       }
     }
   }
 }
 
+bool IsGlyphUnderlined( GlyphIndex index,
+                         const Vector<GlyphRun>& underlineRuns )
+{
+  for( Vector<GlyphRun>::ConstIterator it = underlineRuns.Begin(),
+         endIt = underlineRuns.End();
+         it != endIt;
+       ++it )
+  {
+    const GlyphRun& run = *it;
+
+    if( ( run.glyphIndex <= index ) && ( index < run.glyphIndex + run.numberOfGlyphs ) )
+    {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 } // namespace
 
 TypesetterPtr Typesetter::New( const ModelInterface* const model )
@@ -148,7 +261,7 @@ ViewModel* Typesetter::GetViewModel()
   return mModel;
 }
 
-PixelData Typesetter::Render( const Vector2& size )
+PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat )
 {
   // @todo. This initial implementation for a TextLabel has only one visible page.
 
@@ -180,6 +293,73 @@ PixelData Typesetter::Render( const Vector2& size )
     }
   }
 
+  // Generate the image buffers of the text for each different style first,
+  // then combine all of them together as one final image buffer. We try to
+  // do all of these in CPU only, so that once the final texture is generated,
+  // no calculation is needed in GPU during each frame.
+
+  const unsigned int bufferWidth = static_cast<unsigned int>( size.width );
+  const unsigned int bufferHeight = static_cast<unsigned int>( size.height );
+
+  const unsigned int bufferSizeInt = bufferWidth * bufferHeight;
+  const unsigned int bufferSizeChar = 4u * bufferSizeInt;
+
+  Length numberOfGlyphs = mModel->GetNumberOfGlyphs();
+
+  Devel::PixelBuffer imageBuffer;
+
+  if( RENDER_MASK == behaviour )
+  {
+    // Generate the image buffer as an alpha mask for color glyphs.
+    imageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_MASK, ignoreHorizontalAlignment, pixelFormat, penY, 0u, numberOfGlyphs - 1 );
+  }
+  else if( RENDER_NO_TEXT == behaviour )
+  {
+    // Generate an empty image buffer so that it can been combined with the image buffers for styles
+    imageBuffer = Devel::PixelBuffer::New( bufferWidth, bufferHeight, Pixel::RGBA8888 );
+    memset( imageBuffer.GetBuffer(), 0u, bufferSizeChar );
+  }
+  else
+  {
+    // Generate the image buffer for the text with no style.
+    imageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_NONE, ignoreHorizontalAlignment, pixelFormat, penY, 0u, numberOfGlyphs -1 );
+  }
+
+  if ( ( RENDER_NO_STYLES != behaviour ) && ( RENDER_MASK != behaviour ) )
+  {
+    // @todo. Support shadow and underline for partial text later on.
+
+    // Generate the shadow if enabled
+    const Vector2& shadowOffset = mModel->GetShadowOffset();
+    if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 )
+    {
+      // Create the image buffer for shadow
+      Devel::PixelBuffer shadowImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_SHADOW, ignoreHorizontalAlignment, pixelFormat, penY, 0u, numberOfGlyphs - 1 );
+
+      // Combine the two buffers
+      imageBuffer = CombineImageBuffer( imageBuffer, shadowImageBuffer, bufferWidth, bufferHeight );
+    }
+
+    // Generate the underline if enabled
+    const bool underlineEnabled = mModel->IsUnderlineEnabled();
+    if ( underlineEnabled )
+    {
+      // Create the image buffer for underline
+      Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, penY, 0u, numberOfGlyphs - 1 );
+
+      // Combine the two buffers
+      imageBuffer = CombineImageBuffer( imageBuffer, underlineImageBuffer, bufferWidth, bufferHeight );
+    }
+  }
+
+  // Create the final PixelData for the combined image buffer
+  PixelData pixelData = Devel::PixelBuffer::Convert( imageBuffer );
+
+  return pixelData;
+}
+
+Devel::PixelBuffer Typesetter::CreateImageBuffer( const unsigned int bufferWidth, const unsigned int bufferHeight, Typesetter::Style style, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int verticalOffset, GlyphIndex fromGlyphIndex, GlyphIndex toGlyphIndex )
+{
   // Retrieve lines, glyphs, positions and colors from the view model.
   const Length modelNumberOfLines = mModel->GetNumberOfLines();
   const LineRun* const modelLinesBuffer = mModel->GetLines();
@@ -190,26 +370,26 @@ PixelData Typesetter::Render( const Vector2& size )
   const ColorIndex* const colorIndexBuffer = mModel->GetColorIndices();
 
   // Whether to use the default color.
-  const bool useDefaultColor = NULL == colorsBuffer;
+  const bool useDefaultColor = ( NULL == colorsBuffer );
   const Vector4& defaultColor = mModel->GetDefaultColor();
 
   // Create and initialize the pixel buffer.
   GlyphData glyphData;
-  glyphData.verticalOffset = penY;
-
-  glyphData.width = static_cast<unsigned int>( size.width );
-  glyphData.height = static_cast<unsigned int>( size.height );
-  const unsigned int bufferSizeInt = glyphData.width * glyphData.height;
-  const unsigned int bufferSizeChar = 4u * bufferSizeInt;
-  glyphData.bitmapBuffer = new uint32_t[ bufferSizeInt ]; // This array will get deleted by PixelData because of the DELETE_ARRAY parameter.
-  memset( glyphData.bitmapBuffer, 0u, bufferSizeChar );
+  glyphData.verticalOffset = verticalOffset;
+  glyphData.width = bufferWidth;
+  glyphData.height = bufferHeight;
+  glyphData.bitmapBuffer = Devel::PixelBuffer::New( bufferWidth, bufferHeight, pixelFormat );
 
-  PixelData pixelData = PixelData::New( reinterpret_cast<uint8_t*>( glyphData.bitmapBuffer ),
-                                        bufferSizeChar,
-                                        glyphData.width,
-                                        glyphData.height,
-                                        Pixel::RGBA8888, // The format is RGBA8888 because is the format accepted by the image atlas manager.
-                                        PixelData::DELETE_ARRAY );
+  if ( Pixel::RGBA8888 == pixelFormat )
+  {
+    const unsigned int bufferSizeInt = bufferWidth * bufferHeight;
+    const unsigned int bufferSizeChar = 4u * bufferSizeInt;
+    memset( glyphData.bitmapBuffer.GetBuffer(), 0u, bufferSizeChar );
+  }
+  else
+  {
+    memset( glyphData.bitmapBuffer.GetBuffer(), 0, bufferWidth * bufferHeight );
+  }
 
   // Get a handle of the font client. Used to retrieve the bitmaps of the glyphs.
   TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
@@ -220,15 +400,54 @@ PixelData Typesetter::Render( const Vector2& size )
     const LineRun& line = *( modelLinesBuffer + lineIndex );
 
     // Sets the horizontal offset of the line.
-    glyphData.horizontalOffset = static_cast<int>( line.alignmentOffset );
+    glyphData.horizontalOffset = ignoreHorizontalAlignment ? 0 : static_cast<int>( line.alignmentOffset );
 
     // Increases the vertical offset with the line's ascender.
     glyphData.verticalOffset += static_cast<int>( line.ascender );
 
+    if ( style == Typesetter::STYLE_SHADOW )
+    {
+      const Vector2& shadowOffset = mModel->GetShadowOffset();
+      glyphData.horizontalOffset += shadowOffset.x;
+      if ( lineIndex == 0u )
+      {
+        // Only need to add the vertical shadow offset for once
+        glyphData.verticalOffset += shadowOffset.y;
+      }
+    }
+
+    const bool underlineEnabled = mModel->IsUnderlineEnabled();
+    const Vector4& underlineColor = mModel->GetUnderlineColor();
+    const float underlineHeight = mModel->GetUnderlineHeight();
+
+    // Get the underline runs.
+    const Length numberOfUnderlineRuns = mModel->GetNumberOfUnderlineRuns();
+    Vector<GlyphRun> underlineRuns;
+    underlineRuns.Resize( numberOfUnderlineRuns );
+    mModel->GetUnderlineRuns( underlineRuns.Begin(), 0u, numberOfUnderlineRuns );
+
+    bool thereAreUnderlinedGlyphs = false;
+
+    float currentUnderlinePosition = 0.0f;
+    float currentUnderlineThickness = underlineHeight;
+    float maxUnderlineThickness = currentUnderlineThickness;
+
+    FontId lastUnderlinedFontId = 0;
+
+    float lineExtentLeft = bufferWidth;
+    float lineExtentRight = 0.0f;
+    float baseline = 0.0f;
+
     // Traverses the glyphs of the line.
     const GlyphIndex endGlyphIndex = std::min( numberOfGlyphs, line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs );
     for( GlyphIndex glyphIndex = line.glyphRun.glyphIndex; glyphIndex < endGlyphIndex; ++glyphIndex )
     {
+      if ( glyphIndex < fromGlyphIndex || glyphIndex > toGlyphIndex )
+      {
+        // Ignore any glyph that out of the specified range
+        continue;
+      }
+
       // Retrieve the glyph's info.
       const GlyphInfo* const glyphInfo = glyphsBuffer + glyphIndex;
 
@@ -239,12 +458,84 @@ PixelData Typesetter::Render( const Vector2& size )
         continue;
       }
 
+      const bool underlineGlyph = underlineEnabled || IsGlyphUnderlined( glyphIndex, underlineRuns );
+      thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || underlineGlyph;
+
+      // Are we still using the same fontId as previous
+      if( underlineGlyph && ( glyphInfo->fontId != lastUnderlinedFontId ) )
+      {
+        // We need to fetch fresh font underline metrics
+        FontMetrics fontMetrics;
+        fontClient.GetFontMetrics( glyphInfo->fontId, fontMetrics );
+        currentUnderlinePosition = ceil( fabsf( fontMetrics.underlinePosition ) );
+        const float descender = ceil( fabsf( fontMetrics.descender ) );
+
+        if( fabsf( underlineHeight ) < Math::MACHINE_EPSILON_1000 )
+        {
+          currentUnderlineThickness = fontMetrics.underlineThickness;
+
+          // Ensure underline will be at least a pixel high
+          if ( currentUnderlineThickness < 1.0f )
+          {
+            currentUnderlineThickness = 1.0f;
+          }
+          else
+          {
+            currentUnderlineThickness = ceil( currentUnderlineThickness );
+          }
+        }
+
+        // The underline thickness should be the max underline thickness of all glyphs of the line.
+        if ( currentUnderlineThickness > maxUnderlineThickness )
+        {
+          maxUnderlineThickness = currentUnderlineThickness;
+        }
+
+        // Clamp the underline position at the font descender and check for ( as EFL describes it ) a broken font
+        if( currentUnderlinePosition > descender )
+        {
+          currentUnderlinePosition = descender;
+        }
+
+        if( fabsf( currentUnderlinePosition ) < Math::MACHINE_EPSILON_1000 )
+        {
+          // Move offset down by one ( EFL behavior )
+          currentUnderlinePosition = 1.0f;
+        }
+
+        lastUnderlinedFontId = glyphInfo->fontId;
+      } // underline
+
       // Retrieves the glyph's position.
       const Vector2* const position = positionBuffer + glyphIndex;
+      if ( baseline < position->y + glyphInfo->yBearing )
+      {
+        baseline = position->y + glyphInfo->yBearing;
+      }
+
+      // Calculate the positions of leftmost and rightmost glyphs in the current line
+      if ( position->x < lineExtentLeft)
+      {
+        lineExtentLeft = position->x;
+      }
+
+      if ( position->x + glyphInfo->width > lineExtentRight)
+      {
+        lineExtentRight = position->x + glyphInfo->width;
+      }
 
       // Retrieves the glyph's color.
       const ColorIndex colorIndex = *( colorIndexBuffer + glyphIndex );
-      const Vector4* const color = ( useDefaultColor || ( 0u == colorIndex ) ) ? &defaultColor : colorsBuffer + ( colorIndex - 1u );
+
+      const Vector4* color;
+      if ( style == Typesetter::STYLE_SHADOW )
+      {
+        color = &( mModel->GetShadowColor() );
+      }
+      else
+      {
+        color = ( useDefaultColor || ( 0u == colorIndex ) ) ? &defaultColor : colorsBuffer + ( colorIndex - 1u );
+      }
 
       // Retrieves the glyph's bitmap.
       glyphData.glyphBitmap.buffer = NULL;
@@ -259,11 +550,49 @@ PixelData Typesetter::Render( const Vector2& size )
       {
         TypesetGlyph( glyphData,
                       position,
-                      color );
+                      color,
+                      style,
+                      pixelFormat);
         // delete the glyphBitmap.buffer as it is now copied into glyphData.bitmapBuffer
         delete []glyphData.glyphBitmap.buffer;
         glyphData.glyphBitmap.buffer = NULL;
+      }
+    }
 
+    // Draw the underline from the leftmost glyph to the rightmost glyph
+    if ( thereAreUnderlinedGlyphs && style == Typesetter::STYLE_UNDERLINE )
+    {
+      int underlineYOffset = glyphData.verticalOffset + baseline + currentUnderlinePosition;
+
+      for( unsigned int y = underlineYOffset; y < underlineYOffset + maxUnderlineThickness; y++ )
+      {
+        if( ( y < 0 ) || ( y > bufferHeight - 1 ) )
+        {
+          // Do not write out of bounds.
+          break;
+        }
+
+        for( unsigned int x = glyphData.horizontalOffset + lineExtentLeft; x <= glyphData.horizontalOffset + lineExtentRight; x++ )
+        {
+          if( ( x < 0 ) || ( x > bufferWidth - 1 ) )
+          {
+            // Do not write out of bounds.
+            break;
+          }
+
+          // Always RGBA image for text with styles
+          uint32_t* bitmapBuffer = reinterpret_cast< uint32_t* >( glyphData.bitmapBuffer.GetBuffer() );
+          uint32_t underlinePixel = *( bitmapBuffer + y * glyphData.width + x );
+          uint8_t* underlinePixelBuffer = reinterpret_cast<uint8_t*>( &underlinePixel );
+
+          // Write the underline color to the pixel buffer
+          *( underlinePixelBuffer ) = static_cast<uint8_t>( underlineColor.r * 255.f );
+          *( underlinePixelBuffer + 1u ) = static_cast<uint8_t>( underlineColor.g * 255.f );
+          *( underlinePixelBuffer + 2u ) = static_cast<uint8_t>( underlineColor.b * 255.f );
+          *( underlinePixelBuffer + 3u ) = static_cast<uint8_t>( underlineColor.a * 255.f );
+
+          *( bitmapBuffer + y * glyphData.width + x ) = underlinePixel;
+        }
       }
     }
 
@@ -271,7 +600,70 @@ PixelData Typesetter::Render( const Vector2& size )
     glyphData.verticalOffset += static_cast<int>( -line.descender );
   }
 
-  return pixelData;
+  return glyphData.bitmapBuffer;
+}
+
+Devel::PixelBuffer Typesetter::CombineImageBuffer( Devel::PixelBuffer topPixelBuffer, Devel::PixelBuffer bottomPixelBuffer, const unsigned int bufferWidth, const unsigned int bufferHeight )
+{
+  unsigned char* topBuffer = topPixelBuffer.GetBuffer();
+  unsigned char* bottomBuffer = bottomPixelBuffer.GetBuffer();
+
+  Devel::PixelBuffer combinedPixelBuffer;
+
+  if ( topBuffer == NULL && bottomBuffer == NULL )
+  {
+    // Nothing to do if both buffers are empty.
+    return combinedPixelBuffer;
+  }
+
+  if ( topBuffer == NULL )
+  {
+    // Nothing to do if topBuffer is empty.
+    return bottomPixelBuffer;
+  }
+
+  if ( bottomBuffer == NULL )
+  {
+    // Nothing to do if bottomBuffer is empty.
+    return topPixelBuffer;
+  }
+
+  // Always combine two RGBA images
+  const unsigned int bufferSizeInt = bufferWidth * bufferHeight;
+  const unsigned int bufferSizeChar = 4u * bufferSizeInt;
+
+  combinedPixelBuffer = Devel::PixelBuffer::New( bufferWidth, bufferHeight, Pixel::RGBA8888 );
+  uint8_t* combinedBuffer = reinterpret_cast< uint8_t* >( combinedPixelBuffer.GetBuffer() );
+  memset( combinedBuffer, 0u, bufferSizeChar );
+
+  for (unsigned int pixelIndex = 0; pixelIndex < bufferSizeInt; pixelIndex++)
+  {
+    // If the alpha of the pixel in either buffer is not fully opaque, blend the two pixels.
+    // Otherwise, copy pixel from topBuffer to combinedBuffer.
+
+    unsigned int alphaBuffer1 = topBuffer[pixelIndex*4+3];
+    unsigned int alphaBuffer2 = bottomBuffer[pixelIndex*4+3];
+
+    if ( alphaBuffer1 != 255 || alphaBuffer2 != 255 )
+    {
+      // At least one pixel is not fully opaque
+      // "Over" blend the the pixel from topBuffer with the pixel in bottomBuffer
+      combinedBuffer[pixelIndex*4] = ( topBuffer[pixelIndex*4] * topBuffer[pixelIndex*4+3] / 255 ) + ( bottomBuffer[pixelIndex*4] * bottomBuffer[pixelIndex*4+3] * ( 255 - topBuffer[pixelIndex*4+3] ) / ( 255*255 ) );
+      combinedBuffer[pixelIndex*4+1] = ( topBuffer[pixelIndex*4+1] * topBuffer[pixelIndex*4+3] / 255 ) + ( bottomBuffer[pixelIndex*4+1] * bottomBuffer[pixelIndex*4+3] * ( 255 - topBuffer[pixelIndex*4+3] ) / ( 255*255 ) );
+      combinedBuffer[pixelIndex*4+2] = ( topBuffer[pixelIndex*4+2] * topBuffer[pixelIndex*4+3] / 255 ) + ( bottomBuffer[pixelIndex*4+2] * bottomBuffer[pixelIndex*4+3] * ( 255 - topBuffer[pixelIndex*4+3] ) / ( 255*255 ) );
+      combinedBuffer[pixelIndex*4+3] = topBuffer[pixelIndex*4+3] + ( bottomBuffer[pixelIndex*4+3] * ( 255 - topBuffer[pixelIndex*4+3] ) / 255 );
+    }
+    else
+    {
+      // Copy the pixel from topBuffer to combinedBuffer
+      combinedBuffer[pixelIndex*4] = topBuffer[pixelIndex*4];
+      combinedBuffer[pixelIndex*4+1] = topBuffer[pixelIndex*4+1];
+      combinedBuffer[pixelIndex*4+2] = topBuffer[pixelIndex*4+2];
+      combinedBuffer[pixelIndex*4+3] = topBuffer[pixelIndex*4+3];
+    }
+  }
+
+  return combinedPixelBuffer;
 }
 
 Typesetter::Typesetter( const ModelInterface* const model )
index a5aab65..285348e 100644 (file)
 // EXTERNAL INCLUDES
 #include <dali/public-api/common/intrusive-ptr.h>
 #include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/images/pixel.h>
 #include <dali/public-api/images/pixel-data.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
 
 namespace Dali
 {
@@ -43,6 +46,33 @@ typedef IntrusivePtr<Typesetter> TypesetterPtr;
  */
 class Typesetter : public RefObject
 {
+public:
+
+  /**
+   * @brief Behaviours of how to render the text.
+   */
+  enum RenderBehaviour
+  {
+    RENDER_TEXT_AND_STYLES,  ///< Render both the text and its styles
+    RENDER_NO_TEXT,          ///< Do not render the text itself
+    RENDER_NO_STYLES,        ///< Do not render any styles
+    RENDER_MASK              ///< Render an alpha mask (for color glyphs with no color animation, e.g. emoji)
+  };
+
+  /**
+   * @brief Styles of the text.
+   */
+  enum Style
+  {
+    STYLE_NONE,              ///< No style
+    STYLE_MASK,              ///< Alpha mask
+    STYLE_SHADOW,            ///< Hard shadow
+    STYLE_SOFT_SHADOW,       ///< Soft shadow
+    STYLE_UNDERLINE,         ///< Underline
+    STYLE_OUTLINE,           ///< Outline
+    STYLE_BACKGROUND         ///< Text background
+  };
+
 public: // Constructor.
   /**
    * @brief Creates a Typesetter instance.
@@ -68,15 +98,17 @@ public:
    * Does the following operations:
    * - Finds the visible pages needed to be rendered.
    * - Elide glyphs if needed.
-   * - Retrieves the data buffers from the text model.
-   * - Creates the pixel data used to generate the final image with the given size.
-   * - Traverse the visible glyphs, retrieve their bitmaps and compose the final pixel data.
+   * - Creates image buffers for diffrent text styles with the given size.
+   * - Combines different image buffers to create the pixel data used to generate the final image
    *
    * @param[in] size The renderer size.
+   * @param[in] behaviour The behaviour of how to render the text (i.e. whether to render the text only or the styles only or both).
+   * @param[in] ignoreHorizontalAlignment Whether to ignore the horizontal alignment (i.e. always render as if HORIZONTAL_ALIGN_BEGIN).
+   * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
    *
    * @return A pixel data with the text rendered.
    */
-  PixelData Render( const Vector2& size );
+  PixelData Render( const Vector2& size, RenderBehaviour behaviour = RENDER_TEXT_AND_STYLES, bool ignoreHorizontalAlignment = false, Pixel::Format pixelFormat = Pixel::RGBA8888 );
 
 private:
   /**
@@ -92,6 +124,46 @@ private:
   // Declared private and left undefined to avoid copies.
   Typesetter& operator=( const Typesetter& handle );
 
+  /**
+   * @brief Create the image buffer for the given range of the glyphs in the given style.
+   *
+   * Does the following operations:
+   * - Retrieves the data buffers from the text model.
+   * - Creates the pixel data used to generate the final image with the given size.
+   * - Traverse the visible glyphs, retrieve their bitmaps and compose the final pixel data.
+   *
+   * @param[in] bufferWidth The width of the image buffer.
+   * @param[in] bufferHeight The height of the image buffer.
+   * @param[in] style The style of the text.
+   * @param[in] ignoreHorizontalAlignment Whether to ignore the horizontal alignment, not ignored by default.
+   * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
+   * @param[in] verticalOffset The vertical offset to be added to the glyph's position.
+   * @param[in] fromGlyphIndex The index of the first glyph within the text to be drawn
+   * @param[in] toGlyphIndex The index of the last glyph within the text to be drawn
+   *
+   * @return An image buffer with the text.
+   */
+  Devel::PixelBuffer CreateImageBuffer( const unsigned int bufferWidth, const unsigned int bufferHeight, Typesetter::Style style, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int verticalOffset, TextAbstraction::GlyphIndex fromGlyphIndex, TextAbstraction::GlyphIndex toGlyphIndex );
+
+  /**
+   * @brief Combine the two RGBA image buffers together.
+   *
+   * The top layer buffer will blend over the bottom layer buffer:
+   * - If the pixel is not fully opaque from either buffer, it will be blended with
+   *   the pixel from the other buffer and copied to the combined buffer.
+   * - If the pixels from both buffers are fully opaque, the pixels from the top layer
+   *   buffer will be copied to the combined buffer.
+   *
+   * @param[in] topPixelBuffer The top layer buffer.
+   * @param[in] bottomPixelBuffer The bottom layer buffer.
+   * @param[in] bufferWidth The width of the image buffer.
+   * @param[in] bufferHeight The height of the image buffer.
+   *
+   * @return The combined image buffer with the text.
+   *
+   */
+  Devel::PixelBuffer CombineImageBuffer( Devel::PixelBuffer topPixelBuffer, Devel::PixelBuffer bottomPixelBuffer, const unsigned int bufferWidth, const unsigned int bufferHeightbool );
+
 protected:
 
   /**
@@ -102,6 +174,7 @@ protected:
   virtual ~Typesetter();
 
 private:
+
    ViewModel* mModel;
 };
 
index eb49465..1dcda36 100644 (file)
@@ -86,6 +86,16 @@ const LineRun* const ViewModel::GetLines() const
   return mModel->GetLines();
 }
 
+Length ViewModel::GetNumberOfScripts() const
+{
+  return mModel->GetNumberOfScripts();
+}
+
+const ScriptRun* const ViewModel::GetScriptRuns() const
+{
+  return mModel->GetScriptRuns();
+}
+
 Length ViewModel::GetNumberOfGlyphs() const
 {
   if( mIsTextElided && mModel->IsTextElideEnabled() )
@@ -143,6 +153,41 @@ const Vector4& ViewModel::GetDefaultColor() const
   return mModel->GetDefaultColor();
 }
 
+const Vector2& ViewModel::GetShadowOffset() const
+{
+  return mModel->GetShadowOffset();
+}
+
+const Vector4& ViewModel::GetShadowColor() const
+{
+  return mModel->GetShadowColor();
+}
+
+const Vector4& ViewModel::GetUnderlineColor() const
+{
+  return mModel->GetUnderlineColor();
+}
+
+bool ViewModel::IsUnderlineEnabled() const
+{
+  return mModel->IsUnderlineEnabled();
+}
+
+float ViewModel::GetUnderlineHeight() const
+{
+  return mModel->GetUnderlineHeight();
+}
+
+Length ViewModel::GetNumberOfUnderlineRuns() const
+{
+  return mModel->GetNumberOfUnderlineRuns();
+}
+
+void ViewModel::GetUnderlineRuns( GlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns ) const
+{
+  mModel->GetUnderlineRuns( underlineRuns, index, numberOfRuns );
+}
+
 void ViewModel::ElideGlyphs()
 {
   mIsTextElided = false;
index d178577..e15fa9c 100644 (file)
@@ -97,6 +97,16 @@ public:
   virtual const LineRun* const GetLines() const;
 
   /**
+   * @copydoc ModelInterface::GetNumberOfScripts()
+   */
+  virtual Length GetNumberOfScripts() const;
+
+  /**
+   * @copydoc ModelInterface::GetScriptRuns()
+   */
+  virtual const ScriptRun* const GetScriptRuns() const;
+
+  /**
    * @copydoc ModelInterface::GetNumberOfGlyphs()
    */
   virtual Length GetNumberOfGlyphs() const;
@@ -127,6 +137,41 @@ public:
   virtual const Vector4& GetDefaultColor() const;
 
   /**
+   * @copydoc ModelInterface::GetShadowOffset()
+   */
+  virtual const Vector2& GetShadowOffset() const;
+
+  /**
+   * @copydoc ModelInterface::GetShadowColor()
+   */
+  virtual const Vector4& GetShadowColor() const;
+
+  /**
+   * @copydoc ModelInterface::GetUnderlineColor()
+   */
+  virtual const Vector4& GetUnderlineColor() const;
+
+  /**
+   * @copydoc ModelInterface::IsUnderlineEnabled()
+   */
+  virtual bool IsUnderlineEnabled() const;
+
+  /**
+   * @copydoc ModelInterface::GetUnderlineHeight()
+   */
+  virtual float GetUnderlineHeight() const;
+
+  /**
+   * @copydoc ModelInterface::GetNumberOfUnderlineRuns()
+   */
+  virtual Length GetNumberOfUnderlineRuns() const;
+
+  /**
+   * @copydoc ModelInterface::GetUnderlineRuns()
+   */
+  virtual void GetUnderlineRuns( GlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns ) const;
+
+  /**
    * @brief Does the text elide.
    *
    * It stores a copy of the visible glyphs and removes as many glyphs as needed
index 7875e5c..258fea7 100644 (file)
@@ -1757,14 +1757,14 @@ Vector3 Controller::GetNaturalSize()
     mImpl->UpdateModel( onlyOnceOperations );
 
     // Layout the text for the new width.
-    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT | REORDER );
 
     // Store the actual control's size to restore later.
     const Size actualControlSize = mImpl->mModel->mVisualModel->mControlSize;
 
     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
                 static_cast<OperationsMask>( onlyOnceOperations |
-                                             LAYOUT ),
+                                             LAYOUT | REORDER ),
                 naturalSize.GetVectorXY() );
 
     // Do not do again the only once operations.
@@ -3694,6 +3694,11 @@ void Controller::ResetScrollPosition()
   }
 }
 
+void Controller::SetControlInterface( ControlInterface* controlInterface )
+{
+  mImpl->mControlInterface = controlInterface;
+}
+
 bool Controller::ShouldClearFocusOnEscape() const
 {
   return mImpl->mShouldClearFocusOnEscape;
index 1f64c24..9e193c7 100644 (file)
@@ -999,6 +999,13 @@ public: // Default style & Input style
    */
   const std::string& GetInputOutlineProperties() const;
 
+  /**
+   * @brief Set the control's interface.
+   *
+   * @param[in] controlInterface The control's interface.
+   */
+  void SetControlInterface( ControlInterface* controlInterface );
+
 public: // Queries & retrieves.
 
   /**
index b3eb694..38e1fa2 100644 (file)
@@ -24,6 +24,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/layouts/layout-alignment.h>
 #include <dali-toolkit/internal/text/line-run.h>
+#include <dali-toolkit/internal/text/script-run.h>
 #include <dali-toolkit/internal/text/text-definitions.h>
 
 namespace Dali
@@ -104,6 +105,20 @@ public:
   virtual const LineRun* const GetLines() const = 0;
 
   /**
+   * @brief Retrieves the number of script runs.
+   *
+   * @return The number of script runs.
+   */
+  virtual Length GetNumberOfScripts() const = 0;
+
+  /**
+   * @brief Retrieves the script runs.
+   *
+   * @return A pointer to the vector with the runs of characters with the same script..
+   */
+  virtual const ScriptRun* const GetScriptRuns() const = 0;
+
+  /**
    * @brief Retrieves the number of laid-out glyphs.
    *
    * @return The number of laid-out glyphs.
@@ -144,6 +159,57 @@ public:
    * @return The default color.
    */
   virtual const Vector4& GetDefaultColor() const = 0;
+
+  /**
+   * @brief Retrieves the shadow offset, 0 indicates no shadow.
+   *
+   * @return The shadow offset.
+   */
+  virtual const Vector2& GetShadowOffset() const = 0;
+
+  /**
+   * @brief Retrieves the shadow color.
+   *
+   * @return The shadow color.
+   */
+  virtual const Vector4& GetShadowColor() const = 0;
+
+  /**
+   * @brief Retrieves the underline color.
+   *
+   * @return The underline color.
+   */
+  virtual const Vector4& GetUnderlineColor() const = 0;
+
+  /**
+   * @brief Returns whether underline is enabled or not.
+   *
+   * @return The underline state.
+   */
+  virtual bool IsUnderlineEnabled() const = 0;
+
+  /**
+   * @brief Retrieves the underline height override
+   *
+   * @return Returns the override height for an underline, 0 indicates that adaptor will determine the height
+   */
+  virtual float GetUnderlineHeight() const = 0;
+
+  /**
+   * @brief Retrieves the number of underline runs.
+   *
+   * @return The number of underline runs.
+   */
+  virtual Length GetNumberOfUnderlineRuns() const = 0;
+
+  /**
+   * @brief Retrieves the underline runs.
+   *
+   * @param[out] underlineRuns Pointer to a buffer where the underline runs are copied.
+   * @param[in] index Index of the first underline run to be copied.
+   * @param[in] numberOfRuns Number of underline runs to be copied.
+   */
+  virtual void GetUnderlineRuns( GlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns ) const = 0;
 };
 
 } // namespace Text
index 95f9514..2c00cf8 100644 (file)
@@ -72,6 +72,16 @@ const LineRun* const Model::GetLines() const
   return mVisualModel->mLines.Begin();
 }
 
+Length Model::GetNumberOfScripts() const
+{
+  return mLogicalModel->mScriptRuns.Count();
+}
+
+const ScriptRun* const Model::GetScriptRuns() const
+{
+  return mLogicalModel->mScriptRuns.Begin();
+}
+
 Length Model::GetNumberOfGlyphs() const
 {
   return mVisualModel->mGlyphs.Count();
@@ -102,6 +112,41 @@ const Vector4& Model::GetDefaultColor() const
   return mVisualModel->mTextColor;
 }
 
+const Vector2& Model::GetShadowOffset() const
+{
+  return mVisualModel->mShadowOffset;
+}
+
+const Vector4& Model::GetShadowColor() const
+{
+  return mVisualModel->mShadowColor;
+}
+
+const Vector4& Model::GetUnderlineColor() const
+{
+  return mVisualModel->GetUnderlineColor();
+}
+
+bool Model::IsUnderlineEnabled() const
+{
+  return mVisualModel->IsUnderlineEnabled();
+}
+
+float Model::GetUnderlineHeight() const
+{
+  return mVisualModel->GetUnderlineHeight();
+}
+
+Length Model::GetNumberOfUnderlineRuns() const
+{
+  return mVisualModel->GetNumberOfUnderlineRuns();
+}
+
+void Model::GetUnderlineRuns( GlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns ) const
+{
+  mVisualModel->GetUnderlineRuns( underlineRuns, index, numberOfRuns );
+}
+
 Model::Model()
 : mLogicalModel(),
   mVisualModel(),
index 4256421..a7b0bb8 100644 (file)
@@ -100,6 +100,16 @@ public:
   virtual const LineRun* const GetLines() const;
 
   /**
+   * @copydoc ModelInterface::GetNumberOfScripts()
+   */
+  virtual Length GetNumberOfScripts() const;
+
+  /**
+   * @copydoc ModelInterface::GetScriptRuns()
+   */
+  virtual const ScriptRun* const GetScriptRuns() const;
+
+  /**
    * @copydoc ModelInterface::GetNumberOfGlyphs()
    */
   virtual Length GetNumberOfGlyphs() const;
@@ -129,6 +139,41 @@ public:
    */
   virtual const Vector4& GetDefaultColor() const;
 
+  /**
+   * @copydoc ModelInterface::GetShadowOffset()
+   */
+  virtual const Vector2& GetShadowOffset() const;
+
+  /**
+   * @copydoc ModelInterface::GetShadowColor()
+   */
+  virtual const Vector4& GetShadowColor() const;
+
+  /**
+   * @copydoc ModelInterface::GetUnderlineColor()
+   */
+  virtual const Vector4& GetUnderlineColor() const;
+
+  /**
+   * @copydoc ModelInterface::IsUnderlineEnabled()
+   */
+  virtual bool IsUnderlineEnabled() const;
+
+  /**
+   * @copydoc ModelInterface::GetUnderlineHeight()
+   */
+  virtual float GetUnderlineHeight() const;
+
+  /**
+   * @copydoc ModelInterface::GetNumberOfUnderlineRuns()
+   */
+  virtual Length GetNumberOfUnderlineRuns() const;
+
+  /**
+   * @copydoc ModelInterface::GetUnderlineRuns()
+   */
+  virtual void GetUnderlineRuns( GlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns ) const;
+
 private: // Private contructors & copy operator.
 
   /**
index 590f919..b109661 100644 (file)
 
 // EXTERNAL INCLUDES
 #include <dali/public-api/common/stage.h>
-#include <dali/public-api/images/frame-buffer-image.h>
-#include <dali/public-api/render-tasks/render-task-list.h>
-#include <dali/public-api/rendering/geometry.h>
-#include <dali/public-api/rendering/renderer.h>
-#include <dali/public-api/rendering/sampler.h>
-#include <dali/public-api/rendering/shader.h>
-#include <dali/devel-api/images/texture-set-image.h>
 #include <dali/integration-api/debug.h>
 
 // INTERNAL INCLUDES
@@ -51,30 +44,41 @@ const char* VERTEX_SHADER_SCROLL = DALI_COMPOSE_SHADER(
   attribute mediump vec2 aPosition;\n
   varying highp vec2 vTexCoord;\n
   varying highp float vRatio;\n
-  uniform mediump mat4 uModelMatrix;\n
-  uniform mediump mat4 uViewMatrix;\n
-  uniform mediump mat4 uProjection;\n
   uniform mediump vec3 uSize;\n
   uniform mediump float uDelta;\n
-  uniform mediump vec2 uTextureSize;
+  uniform mediump vec2 uTextureSize;\n
   uniform mediump float uGap;\n
-  uniform mediump float uAlign;\n
+  uniform mediump float uHorizontalAlign;\n
+  uniform mediump float uVerticalAlign;\n
+  \n
+  uniform mediump mat4 uModelMatrix;\n
+  uniform mediump mat4 uViewMatrix;\n
+  uniform mediump mat4 uProjection;\n
   \n
+  //Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+
   void main()\n
   {\n
-    {\n
-      highp vec4 vertexPosition = vec4(aPosition*uSize.xy, 0.0, 1.0);\n
-      vertexPosition = uViewMatrix *  uModelMatrix  * vertexPosition ;\n
-      vertexPosition.x = floor( vertexPosition.x ) + 0.5;
-      vertexPosition.y = floor( vertexPosition.y ) + 0.5;
-      float smallTextPadding = max(uSize.x - uTextureSize.x, 0. );\n
-      float gap = max( uGap, smallTextPadding );\n
-      float delta = floor ( uDelta ) + 0.5;
-      vTexCoord.x = ( delta  + ( uAlign * ( uTextureSize.x - uSize.x ) ) + (  aPosition.x * uSize.x ) )/ ( uTextureSize.x + gap );\n
-      vTexCoord.y = ( 0.5 + floor(  aPosition.y * uSize.y ) )/ ( uTextureSize.y ) ;\n
-      vRatio = uTextureSize.x / ( uTextureSize.x + gap );\n
-      gl_Position = uProjection * vertexPosition;
-    }\n
+    mediump vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy );\n
+    mediump vec2 visualSize = mix( uSize.xy * size, size, offsetSizeMode.zw );\n
+    \n
+    mediump float smallTextPadding = max( visualSize.x - uTextureSize.x, 0. );\n
+    mediump float gap = max( uGap, smallTextPadding );\n
+    mediump float delta = floor ( uDelta ) + 0.5;\n
+    vTexCoord.x = ( delta + uHorizontalAlign * ( uTextureSize.x - visualSize.x ) + floor( aPosition.x * visualSize.x ) + 0.5 - gap * 0.5 ) / ( uTextureSize.x + gap ) + 0.5;\n
+    vTexCoord.y = ( uVerticalAlign * ( uTextureSize.y - visualSize.y ) + floor( aPosition.y * visualSize.y ) + 0.5 ) / ( uTextureSize.y ) + 0.5;\n
+    vRatio = uTextureSize.x / ( uTextureSize.x + gap );\n
+    \n
+    mediump vec4 vertexPosition = vec4( floor( ( aPosition + anchorPoint ) * visualSize + ( visualOffset + origin ) * uSize.xy ), 0.0, 1.0 );\n
+    mediump vec4 nonAlignedVertex = uViewMatrix * uModelMatrix * vertexPosition;\n
+    mediump vec4 pixelAlignedVertex = vec4 ( floor( nonAlignedVertex.xyz ), 1.0 );\n
+    \n
+    gl_Position = uProjection * pixelAlignedVertex;\n
   }\n
 );
 
@@ -88,7 +92,7 @@ const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
     highp vec2 texCoord;\n
     texCoord.y = vTexCoord.y;\n
     texCoord.x = fract( vTexCoord.x ) / vRatio;\n
-    if ( texCoord.x > 1.0 )\n
+    if ( texCoord.x > 1.0 || texCoord.y > 1.0 )\n
       discard;\n
     \n
     gl_FragColor = texture2D( sTexture, texCoord );\n
@@ -96,146 +100,46 @@ const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
 );
 
 /**
- * @brief How the text should be aligned when scrolling the text.
+ * @brief How the text should be aligned horizontally when scrolling the text.
  *
- * 0.0f aligns the text to the left, 1.0f aligns the text to the right.
- * The final alignment depends on three factors:
+ * -0.5f aligns the text to the left, 0.0f aligns the text to the center, 0.5f aligns the text to the right.
+ * The final alignment depends on two factors:
  *   1) The alignment value of the text label (Use Text::Layout::HorizontalAlignment enumerations).
  *   2) The text direction, i.e. whether it's LTR or RTL (0 = LTR, 1 = RTL).
- *   3) Whether the text is greater than the size of the control ( 0 = Text width <= Control width, 1 = Text width > Control width ).
  */
-const float ALIGNMENT_TABLE[ Text::Layout::HORIZONTAL_ALIGN_COUNT ][ 2 ][ 2 ] =
+const float HORIZONTAL_ALIGNMENT_TABLE[ Text::Layout::HORIZONTAL_ALIGN_COUNT ][ 2 ] =
 {
   // HORIZONTAL_ALIGN_BEGIN
   {
-    { // LTR
-      0.0f, // Text width <= Control width
-      0.0f  // Text width >  Control width
-    },
-    { // RTL
-      1.0f, // Text width <= Control width
-      1.0f  // Text width >  Control width
-    }
+    -0.5f, // LTR
+    0.5f   // RTL
   },
 
   // HORIZONTAL_ALIGN_CENTER
   {
-    { // LTR
-      0.5f, // Text width <= Control width
-      0.0f  // Text width >  Control width
-    },
-    { // RTL
-      0.5f, // Text width <= Control width
-      1.0f  // Text width >  Control width
-    }
+    0.0f,  // LTR
+    0.0f   // RTL
   },
 
   // HORIZONTAL_ALIGN_END
   {
-    { // LTR
-      1.0f, // Text width <= Control width
-      0.0f  // Text width >  Control width
-    },
-    { // RTL
-      0.0f, // Text width <= Control width
-      1.0f  // Text width >  Control width
-    }
+    0.5f,  // LTR
+    -0.5f  // RTL
   }
 };
 
 /**
- * @brief Create and set up a camera for the render task to use
- *
- * @param[in] sizeOfTarget size of the source camera to look at
- * @param[out] offscreenCamera custom camera
- */
-void CreateCameraActor( const Size& sizeOfTarget, CameraActor& offscreenCamera )
-{
-  offscreenCamera = CameraActor::New();
-  offscreenCamera.SetOrthographicProjection( sizeOfTarget );
-  offscreenCamera.SetInvertYAxis( true );
-}
-
-/**
- * @brief Create a render task
+ * @brief How the text should be aligned vertically when scrolling the text.
  *
- * @param[in] sourceActor actor to be used as source
- * @param[in] cameraActor camera looking at source
- * @param[in] offscreenTarget resulting image from render task
- * @param[out] renderTask render task that has been setup
+ * -0.5f aligns the text to the top, 0.0f aligns the text to the center, 0.5f aligns the text to the bottom.
+ * The alignment depends on the alignment value of the text label (Use Text::Layout::VerticalAlignment enumerations).
  */
-void CreateRenderTask( Actor sourceActor, CameraActor cameraActor , FrameBufferImage offscreenTarget, RenderTask& renderTask )
+const float VERTICAL_ALIGNMENT_TABLE[ Text::Layout::VERTICAL_ALIGN_COUNT ] =
 {
-  Stage stage = Stage::GetCurrent();
-  RenderTaskList taskList = stage.GetRenderTaskList();
-  renderTask = taskList.CreateTask();
-  renderTask.SetSourceActor( sourceActor );
-  renderTask.SetExclusive( true );
-  renderTask.SetInputEnabled( false );
-  renderTask.SetClearEnabled( true );
-  renderTask.SetCameraActor( cameraActor );
-  renderTask.SetTargetFrameBuffer( offscreenTarget );
-  renderTask.SetClearColor( Color::TRANSPARENT );
-  renderTask.SetCullMode( false );
-}
-
-/**
- * @brief Create quad geometry for the mesh
- *
- * @param[out] geometry quad geometry that can be used for a mesh
- */
-void CreateGeometry( Geometry& geometry )
-{
-  struct QuadVertex { Vector2 position;  };
-
-  QuadVertex quadVertexData[4] =
-  {
-      { Vector2( 0.0f, 0.0f) },
-      { Vector2( 1.0f, 0.0f) },
-      { Vector2( 0.0f, 1.0f) },
-      { Vector2( 1.0f, 1.0f) },
-  };
-
-  const unsigned short indices[6] =
-  {
-     3,1,0,0,2,3
-  };
-
-  Property::Map quadVertexFormat;
-  quadVertexFormat["aPosition"] = Property::VECTOR2;
-  PropertyBuffer quadVertices = PropertyBuffer::New( quadVertexFormat );
-  quadVertices.SetData(quadVertexData, 4 );
-
-  geometry = Geometry::New();
-  geometry.AddVertexBuffer( quadVertices );
-  geometry.SetIndexBuffer( indices, sizeof(indices)/sizeof(indices[0]) );
-}
-
-
-/**
- * @brief Create a renderer
- *
- * @param[in] frameBufferImage texture to be used
- * @param[out] renderer mesh renderer using the supplied texture
- */
-void CreateRenderer( FrameBufferImage frameBufferImage, Dali::Renderer& renderer )
-{
-  Shader shader = Shader::New( VERTEX_SHADER_SCROLL , FRAGMENT_SHADER, Shader::Hint::NONE );
-
-  Sampler sampler = Sampler::New();
-  sampler.SetFilterMode(FilterMode::LINEAR, FilterMode::LINEAR );
-
-  TextureSet textureSet = TextureSet::New();
-  TextureSetImage( textureSet, 0u, frameBufferImage );
-  textureSet.SetSampler( 0u, sampler );
-
-  Geometry meshGeometry;
-  CreateGeometry( meshGeometry );
-
-  renderer = Renderer::New( meshGeometry, shader );
-  renderer.SetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true );
-  renderer.SetTextures( textureSet );
-}
+  -0.5f, // VERTICAL_ALIGN_TOP
+  0.0f,  // VERTICAL_ALIGN_CENTER
+  0.5f   // VERTICAL_ALIGN_BOTTOM
+};
 
 } // namespace
 
@@ -311,7 +215,6 @@ void TextScroller::StopScrolling()
       case DevelTextLabel::AutoScrollStopMode::IMMEDIATE:
       {
         mScrollAnimation.Stop();
-        CleanUp();
         mScrollerInterface.ScrollingFinished();
         break;
       }
@@ -333,38 +236,28 @@ DevelTextLabel::AutoScrollStopMode::Type TextScroller::GetStopMode() const
   return mStopMode;
 }
 
-Actor TextScroller::GetSourceCamera() const
-{
-  return mOffscreenCameraActor;
-}
-
-Actor TextScroller::GetScrollingText() const
-{
-  return mScrollingTextActor;
-}
-
-TextScroller::TextScroller( ScrollerInterface& scrollerInterface ) : mScrollerInterface( scrollerInterface ),
-                            mScrollDeltaIndex( Property::INVALID_INDEX ),
-                            mScrollSpeed( MINIMUM_SCROLL_SPEED ),
-                            mLoopCount( 1 ),
-                            mLoopDelay( 0.0f ),
-                            mWrapGap( 0.0f ),
-                            mStopMode( DevelTextLabel::AutoScrollStopMode::FINISH_LOOP )
+TextScroller::TextScroller( ScrollerInterface& scrollerInterface )
+: mScrollerInterface( scrollerInterface ),
+  mScrollDeltaIndex( Property::INVALID_INDEX ),
+  mScrollSpeed( MINIMUM_SCROLL_SPEED ),
+  mLoopCount( 1 ),
+  mLoopDelay( 0.0f ),
+  mWrapGap( 0.0f ),
+  mStopMode( DevelTextLabel::AutoScrollStopMode::FINISH_LOOP )
 {
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller Default Constructor\n" );
 }
 
 TextScroller::~TextScroller()
 {
-  CleanUp();
 }
 
-void TextScroller::SetParameters( Actor sourceActor, const Size& controlSize, const Size& offScreenSize, CharacterDirection direction, float alignmentOffset, Layout::HorizontalAlignment horizontalAlignment )
+void TextScroller::SetParameters( Actor scrollingTextActor, Renderer renderer, TextureSet textureSet, const Size& controlSize, const Size& textNaturalSize, CharacterDirection direction, Layout::HorizontalAlignment horizontalAlignment, Layout::VerticalAlignment verticalAlignment )
 {
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetParameters controlSize[%f,%f] offscreenSize[%f,%f] direction[%d] alignmentOffset[%f]\n",
-                 controlSize.x, controlSize.y, offScreenSize.x, offScreenSize.y, direction, alignmentOffset );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetParameters controlSize[%f,%f] offscreenSize[%f,%f] direction[%d]\n",
+                 controlSize.x, controlSize.y, textNaturalSize.x, textNaturalSize.y, direction );
 
-  CleanUp(); //  If already scrolling then restart with new parameters
+  mRenderer = renderer;
 
   float animationProgress = 0.0f;
   int   remainedLoop = mLoopCount;
@@ -381,114 +274,69 @@ void TextScroller::SetParameters( Actor sourceActor, const Size& controlSize, co
       }
     }
     mScrollAnimation.Clear();
-  }
-
-  FrameBufferImage offscreenRenderTargetForText = FrameBufferImage::New( offScreenSize.width, offScreenSize.height, Pixel::RGBA8888 );
-  Renderer renderer;
 
-  CreateCameraActor( offScreenSize, mOffscreenCameraActor );
-  CreateRenderer( offscreenRenderTargetForText, renderer );
-  CreateRenderTask( sourceActor, mOffscreenCameraActor, offscreenRenderTargetForText, mRenderTask );
-
-  float xPosition = 0.0f;
-  switch( horizontalAlignment )
-  {
-    case Layout::HORIZONTAL_ALIGN_BEGIN:
-    {
-      // Reposition camera to match alignment of target, RTL text has direction=true
-      if ( direction )
-      {
-        xPosition = alignmentOffset + offScreenSize.width * 0.5f;
-      }
-      else
-      {
-        xPosition = offScreenSize.width * 0.5f;
-      }
-      break;
-    }
-
-    case Layout::HORIZONTAL_ALIGN_CENTER:
-    {
-      xPosition = controlSize.width * 0.5f;
-      break;
-    }
-
-    case Layout::HORIZONTAL_ALIGN_END:
-    {
-      // Reposition camera to match alignment of target, RTL text has direction=true
-      if ( direction )
-      {
-        xPosition = offScreenSize.width * 0.5f;
-      }
-      else
-      {
-        xPosition = alignmentOffset + offScreenSize.width * 0.5f;
-      }
-      break;
-    }
+    // Reset to the original shader and texture before scrolling
+    mRenderer.SetShader(mShader);
+    mRenderer.SetTextures( mTextureSet );
   }
 
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetParameters xPosition[%f]\n", xPosition );
+  mShader = mRenderer.GetShader();
+  mTextureSet = mRenderer.GetTextures();
 
-  mOffscreenCameraActor.SetX( xPosition );
-  mOffscreenCameraActor.SetY( offScreenSize.height * 0.5f );
+  // Set the shader and texture for scrolling
+  Shader shader = Shader::New( VERTEX_SHADER_SCROLL, FRAGMENT_SHADER, Shader::Hint::NONE );
+  mRenderer.SetShader( shader );
+  mRenderer.SetTextures( textureSet );
 
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetParameters mWrapGap[%f]\n", mWrapGap );
 
-  const float align = ALIGNMENT_TABLE[ horizontalAlignment ][ direction ][ offScreenSize.width > controlSize.width ];
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetParameters align[%f]\n", align );
+  const float horizontalAlign = HORIZONTAL_ALIGNMENT_TABLE[ horizontalAlignment ][ direction ];
+  const float verticalAlign = VERTICAL_ALIGNMENT_TABLE[ verticalAlignment ];
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetParameters horizontalAlign[%f], verticalAlign[%f]\n", horizontalAlign, verticalAlign );
 
-  mScrollingTextActor = Actor::New();
-  mScrollingTextActor.AddRenderer( renderer );
-  mScrollingTextActor.RegisterProperty( "uTextureSize", offScreenSize );
-  mScrollingTextActor.RegisterProperty( "uAlign", align );
-  mScrollingTextActor.RegisterProperty( "uGap", mWrapGap );
-  mScrollingTextActor.SetSize( controlSize.width, std::min( offScreenSize.height, controlSize.height ) );
-  mScrollDeltaIndex = mScrollingTextActor.RegisterProperty( "uDelta", 0.0f );
+  scrollingTextActor.RegisterProperty( "uTextureSize", textNaturalSize );
+  scrollingTextActor.RegisterProperty( "uHorizontalAlign", horizontalAlign );
+  scrollingTextActor.RegisterProperty( "uVerticalAlign", verticalAlign );
+  scrollingTextActor.RegisterProperty( "uGap", mWrapGap );
+  mScrollDeltaIndex = scrollingTextActor.RegisterProperty( "uDelta", 0.0f );
 
-  float scrollAmount = std::max( offScreenSize.width + mWrapGap, controlSize.width );
+  float scrollAmount = std::max( textNaturalSize.width + mWrapGap, controlSize.width );
   float scrollDuration =  scrollAmount / mScrollSpeed;
 
   if ( direction  )
   {
-     scrollAmount = -scrollAmount; // reverse direction of scrollung
+     scrollAmount = -scrollAmount; // reverse direction of scrolling
   }
 
-  StartScrolling( scrollAmount, scrollDuration, remainedLoop );
+  StartScrolling( scrollingTextActor, scrollAmount, scrollDuration, remainedLoop );
   mScrollAnimation.SetCurrentProgress(animationProgress);
 }
 
 void TextScroller::AutoScrollAnimationFinished( Dali::Animation& animation )
 {
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::AutoScrollAnimationFinished\n" );
-  CleanUp();
   mScrollerInterface.ScrollingFinished();
+
+  // Revert to the original shader and texture after scrolling
+  mRenderer.SetShader(mShader);
+  if ( mTextureSet )
+  {
+    mRenderer.SetTextures( mTextureSet );
+  }
 }
 
-void TextScroller::StartScrolling( float scrollAmount, float scrollDuration, int loopCount )
+void TextScroller::StartScrolling( Actor scrollingTextActor, float scrollAmount, float scrollDuration, int loopCount )
 {
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::StartScrolling scrollAmount[%f] scrollDuration[%f], loop[%d] speed[%d]\n", scrollAmount, scrollDuration, loopCount, mScrollSpeed );
 
   mScrollAnimation = Animation::New( scrollDuration );
-  mScrollAnimation.AnimateTo( Property( mScrollingTextActor, mScrollDeltaIndex ), scrollAmount, TimePeriod( mLoopDelay, scrollDuration ) );
+  mScrollAnimation.AnimateTo( Property( scrollingTextActor, mScrollDeltaIndex ), scrollAmount, TimePeriod( mLoopDelay, scrollDuration ) );
   mScrollAnimation.SetEndAction( Animation::Discard );
   mScrollAnimation.SetLoopCount( loopCount );
   mScrollAnimation.FinishedSignal().Connect( this, &TextScroller::AutoScrollAnimationFinished );
   mScrollAnimation.Play();
 }
 
-void TextScroller::CleanUp()
-{
-  if ( Stage::IsInstalled() )
-  {
-    Stage stage = Stage::GetCurrent();
-    RenderTaskList taskList = stage.GetRenderTaskList();
-    UnparentAndReset( mScrollingTextActor );
-    UnparentAndReset( mOffscreenCameraActor );
-    taskList.RemoveTask( mRenderTask );
-  }
-}
-
 } // namespace Text
 
 } // namespace Toolkit
index 2d611bb..b8dc10f 100644 (file)
@@ -22,6 +22,7 @@
 #include <dali/public-api/actors/camera-actor.h>
 #include <dali/public-api/animation/animation.h>
 #include <dali/public-api/render-tasks/render-task.h>
+#include <dali/public-api/rendering/renderer.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
@@ -60,14 +61,16 @@ public:
   /**
    * @brief Set parameters relating to source required for scrolling
    *
-   * @param[in] sourceActor source actor to be scrolled
+   * @param[in] scrollingTextActor actor containing the text to be scrolled
+   * @param[in] renderer renderer to render the text
+   * @param[in] textureSet texture of the text to be scrolled
    * @param[in] controlSize size of the control to scroll within
-   * @param[in] offScreenSize size of the sourceActor
+   * @param[in] textNaturalSize natural size of the text
    * @param[in] direction text direction true for right to left text
-   * @param[in] alignmentOffset alignment of source text
-   *
+   * @param[in] horizontalAlignment horizontal alignment of the text
+   * @param[in] verticalAlignment vertical alignment of the text
    */
-  void SetParameters( Actor sourceActor, const Size& controlSize, const Size& offScreenSize, CharacterDirection direction, float alignmentOffset, Layout::HorizontalAlignment horizontalAlignment );
+  void SetParameters( Actor scrollingTextActor, Dali::Renderer renderer, TextureSet textureSet, const Size& controlSize, const Size& offScreenSize, CharacterDirection direction, Layout::HorizontalAlignment horizontalAlignment, Layout::VerticalAlignment verticalAlignment );
 
   /**
    * @brief Set the gap distance to elapse before the text wraps around
@@ -134,18 +137,6 @@ public:
    */
   DevelTextLabel::AutoScrollStopMode::Type GetStopMode() const;
 
-  /**
-   * @brief Get the camera used to look at source, should be added to the parent of target actor.
-   * @return camera Actor
-   */
-  Actor GetSourceCamera() const;
-
-  /**
-   * @brief Get the resulting scrolling text actor, add to target actor which will show scrolling text
-   * @return mesh Actor
-   */
-  Actor GetScrollingText() const;
-
 private: // Implementation
 
   /**
@@ -172,25 +163,21 @@ private: // Implementation
 
   /**
    * @brief variables required to set up scrolling animation
+   * @param[in] scrollingTextActor actor that shows scrolling text
    * @param[in] scrollAmount distance to animate text for the given duration
    * @param[in] scrollDuration duration of aninmation
    * @param[in] loopCount number of times to loop the scrolling text
    */
-  void StartScrolling( float scrollAmount, float scrollDuration, int loopCount );
-
-  /**
-   * @brief When scrolling ended, the actors are cleaned up so no longer staged.
-   */
-  void CleanUp();
+  void StartScrolling( Actor scrollingTextActor, float scrollAmount, float scrollDuration, int loopCount );
 
 private:
 
-  RenderTask         mRenderTask;               // Renders full text to a FrameBuffer which is then scrolled.
-  CameraActor        mOffscreenCameraActor;     // Camera used by render task
-  Actor              mScrollingTextActor;       // Actor used to show scrolling text
   ScrollerInterface& mScrollerInterface;        // Interface implemented by control that requires scrolling
   Property::Index    mScrollDeltaIndex;         // Property used by shader to represent distance to scroll
   Animation          mScrollAnimation;          // Animation used to update the mScrollDeltaIndex
+  Dali::Renderer     mRenderer;                 // Renderer used to render the text
+  Shader             mShader;                   // Shader originally used by the renderer while not scrolling
+  TextureSet         mTextureSet;               // Texture originally used by the renderer while not scrolling
 
   int   mScrollSpeed;                                   ///< Speed which text should automatically scroll at
   int   mLoopCount;                                     ///< Number of time the text should scroll
index 754b06d..9e8d0be 100644 (file)
@@ -384,7 +384,7 @@ Length View::GetNumberOfUnderlineRuns() const
 {
   if( mImpl->mVisualModel )
   {
-    return mImpl->mVisualModel->mUnderlineRuns.Count();
+    return mImpl->mVisualModel->GetNumberOfUnderlineRuns();
   }
 
   return 0u;
index 2ee0bab..1b114c4 100644 (file)
@@ -390,6 +390,11 @@ float VisualModel::GetUnderlineHeight() const
   return mUnderlineHeight;
 }
 
+Length VisualModel::GetNumberOfUnderlineRuns() const
+{
+  return mUnderlineRuns.Count();
+}
+
 void VisualModel::ClearCaches()
 {
   mCachedLineIndex = 0u;
index 0874c05..6356f32 100644 (file)
@@ -280,6 +280,13 @@ public:
    */
   float GetUnderlineHeight() const;
 
+  /**
+   * @brief Retrieves the number of underline runs.
+   *
+   * @return The number of underline runs.
+   */
+  Length GetNumberOfUnderlineRuns() const;
+
 protected:
 
   /**
index 7c933ce..9f775a1 100644 (file)
@@ -477,7 +477,7 @@ TextureSet AnimatedImageVisual::PrepareAnimatedGifImage()
   // load from image file
   std::vector<Dali::PixelData> pixelDataList;
 
-  if( mImageUrl.IsLocal() )
+  if( mImageUrl.IsLocalResource() )
   {
     if( Dali::LoadAnimatedGifFromFile( mImageUrl.GetUrl().c_str() , pixelDataList, mFrameDelayContainer ) )
     {
index b30a11a..4c59447 100644 (file)
@@ -19,7 +19,7 @@
 
 // EXTERNAL INCLUDES
 #include <dali-toolkit/internal/visuals/animated-image/image-cache.h>
-#include <dali-toolkit/internal/visuals/texture-manager.h>
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
 
 namespace Dali
 {
index 5061d76..12e89e9 100644 (file)
@@ -19,7 +19,7 @@
 
 // EXTERNAL INCLUDES
 #include <dali-toolkit/internal/visuals/texture-upload-observer.h>
-#include <dali-toolkit/internal/visuals/texture-manager.h>
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
 
 namespace Dali
 {
index 6f5607c..1aed961 100644 (file)
@@ -21,7 +21,7 @@
 
 #include <dali/devel-api/common/circular-queue.h>
 #include <dali-toolkit/internal/visuals/animated-image/image-cache.h>
-#include <dali-toolkit/internal/visuals/texture-manager.h>
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
 
 namespace Dali
 {
index dcb222d..ee0042a 100644 (file)
@@ -34,7 +34,7 @@
 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
-#include <dali-toolkit/internal/visuals/texture-manager.h>
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
@@ -554,7 +554,7 @@ void ImageVisual::GetNaturalSize( Vector2& naturalSize )
   }
   else if( mImageUrl.IsValid() )
   {
-    if( mImageUrl.GetLocation() == VisualUrl::LOCAL )
+    if( mImageUrl.GetProtocolType() == VisualUrl::LOCAL )
     {
       ImageDimensions dimensions = Dali::GetClosestImageSize( mImageUrl.GetUrl() );
 
@@ -787,7 +787,7 @@ void ImageVisual::InitializeRenderer()
 {
   mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
 
-  if( ! mImpl->mCustomShader && mImageUrl.GetLocation() == VisualUrl::LOCAL )
+  if( ! mImpl->mCustomShader && mImageUrl.GetProtocolType() == VisualUrl::LOCAL )
   {
     bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
 
index 9235545..7be7301 100755 (executable)
@@ -264,7 +264,7 @@ void NPatchVisual::GetNaturalSize( Vector2& naturalSize )
   naturalSize.y = 0u;
 
   // load now if not already loaded
-  if( NPatchLoader::UNINITIALIZED_ID == mId && mImageUrl.IsLocal() )
+  if( NPatchLoader::UNINITIALIZED_ID == mId && mImageUrl.IsLocalResource() )
   {
     mId = mLoader.Load( mImageUrl.GetUrl(), mBorder );
   }
@@ -304,7 +304,7 @@ void NPatchVisual::DoSetProperties( const Property::Map& propertyMap )
 void NPatchVisual::DoSetOnStage( Actor& actor )
 {
   // load when first go on stage
-  if( NPatchLoader::UNINITIALIZED_ID == mId && mImageUrl.IsLocal() )
+  if( NPatchLoader::UNINITIALIZED_ID == mId && mImageUrl.IsLocalResource() )
   {
     mId = mLoader.Load( mImageUrl.GetUrl(), mBorder );
   }
index 1e95223..ef2fdae 100644 (file)
@@ -155,7 +155,7 @@ void SvgVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
 void SvgVisual::ParseFromUrl( const VisualUrl& imageUrl )
 {
   mImageUrl = imageUrl;
-  if( mImageUrl.IsLocal() )
+  if( mImageUrl.IsLocalResource() )
   {
     Vector2 dpi = Stage::GetCurrent().GetDpi();
     float meanDpi = (dpi.height + dpi.width) * 0.5f;
index 7ce455e..c90c727 100644 (file)
 // CLASS HEADER
 #include <dali-toolkit/internal/visuals/text/text-visual.h>
 
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/constraints.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
 // INTERNAL HEADER
 #include <dali-toolkit/devel-api/visuals/text-visual-properties.h>
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
@@ -27,6 +31,8 @@
 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
 #include <dali-toolkit/internal/text/text-font-style.h>
+#include <dali-toolkit/internal/text/text-effects-style.h>
+#include <dali-toolkit/internal/text/script-run.h>
 
 namespace Dali
 {
@@ -49,6 +55,8 @@ const char * const HORIZONTAL_ALIGNMENT_PROPERTY( "horizontalAlignment" );
 const char * const VERTICAL_ALIGNMENT_PROPERTY( "verticalAlignment" );
 const char * const TEXT_COLOR_PROPERTY( "textColor" );
 const char * const ENABLE_MARKUP_PROPERTY( "enableMarkup" );
+const char * const SHADOW_PROPERTY( "shadow" );
+const char * const UNDERLINE_PROPERTY( "underline" );
 
 const Scripting::StringEnum HORIZONTAL_ALIGNMENT_STRING_TABLE[] =
 {
@@ -74,7 +82,11 @@ std::string GetHorizontalAlignment( Toolkit::Text::Layout::HorizontalAlignment a
                                                                                                 HORIZONTAL_ALIGNMENT_STRING_TABLE,
                                                                                                 HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT );
 
-  return std::string( name );
+  if( name )
+  {
+    return std::string( name );
+  }
+  return std::string();
 }
 
 std::string GetVerticalAlignment( Toolkit::Text::Layout::VerticalAlignment alignment )
@@ -83,21 +95,25 @@ std::string GetVerticalAlignment( Toolkit::Text::Layout::VerticalAlignment align
                                                                                                 VERTICAL_ALIGNMENT_STRING_TABLE,
                                                                                                 VERTICAL_ALIGNMENT_STRING_TABLE_COUNT );
 
-  return std::string( name );
+  if( name )
+  {
+    return std::string( name );
+  }
+  return std::string();
 }
 
 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
   attribute mediump vec2 aPosition;\n
   uniform mediump mat4 uMvpMatrix;\n
   uniform mediump vec3 uSize;\n
-  uniform mediump vec4 pixelArea;
+  uniform mediump vec4 pixelArea;\n
 
   uniform mediump mat4 uModelMatrix;\n
   uniform mediump mat4 uViewMatrix;\n
   uniform mediump mat4 uProjection;\n
 
   varying mediump vec2 vTexCoord;\n
-  \n
+
   //Visual size and offset
   uniform mediump vec2 offset;\n
   uniform mediump vec2 size;\n
@@ -123,19 +139,54 @@ const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
   }\n
 );
 
-const char* FRAGMENT_SHADER_ATLAS_CLAMP = DALI_COMPOSE_SHADER(
-    varying mediump vec2 vTexCoord;\n
-    uniform sampler2D sTexture;\n
-    uniform mediump vec4 uAtlasRect;\n
-    uniform lowp vec4 uColor;\n
-    uniform lowp vec3 mixColor;\n
-    uniform lowp float opacity;\n
-    \n
-    void main()\n
-    {\n
-      mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );\n
-      gl_FragColor = texture2D( sTexture, texCoord ) * uColor * vec4( mixColor, opacity );\n
-    }\n
+const char* FRAGMENT_SHADER_ATLAS_CLAMP_RGBA = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform sampler2D sStyle;\n
+  uniform sampler2D sMask;\n
+  uniform lowp float uHasMultipleTextColors;\n
+  uniform lowp vec4 uTextColorAnimatable;\n
+  uniform mediump vec4 uAtlasRect;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  uniform lowp float opacity;\n
+  \n
+  void main()\n
+  {\n
+    mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );\n
+    mediump vec4 textTexture = texture2D( sTexture, texCoord );\n
+    mediump vec4 styleTexture = texture2D( sStyle, texCoord );\n
+    mediump vec4 maskTexture = texture2D( sMask, texCoord );\n
+
+    // Set the color of non-transparent pixel in text to what it is animated to.
+    // Markup text with multiple text colors are not animated (but can be supported later on if required).
+    // Emoji color are not animated.
+    mediump vec4 textColor = textTexture * textTexture.a;\n
+    mediump float vstep = step( 0.0001, textColor.a );\n
+    textColor.rgb = mix( textColor.rgb, uTextColorAnimatable.rgb, vstep * maskTexture.a * ( 1.0 - uHasMultipleTextColors ) );\n
+
+    // Draw the text as overlay above the style
+    gl_FragColor = ( textColor + styleTexture * ( 1.0 - textTexture.a ) ) * uColor * vec4( mixColor, opacity );\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER_ATLAS_CLAMP_L8 = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform lowp vec4 uTextColorAnimatable;\n
+  uniform mediump vec4 uAtlasRect;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  uniform lowp float opacity;\n
+  \n
+  void main()\n
+  {\n
+    mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );\n
+    mediump float textTexture = texture2D( sTexture, texCoord ).r;\n
+
+    // Set the color of the text to what it is animated to.
+    gl_FragColor = uTextColorAnimatable * textTexture * uColor * vec4( mixColor, opacity );\n
+  }\n
 );
 
 /**
@@ -188,6 +239,14 @@ Dali::Property::Index StringKeyToIndexKey( const std::string& stringKey )
   {
     result = Toolkit::TextVisual::Property::ENABLE_MARKUP;
   }
+  else if( stringKey == SHADOW_PROPERTY )
+  {
+    result = Toolkit::TextVisual::Property::SHADOW;
+  }
+  else if( stringKey == UNDERLINE_PROPERTY )
+  {
+    result = Toolkit::TextVisual::Property::UNDERLINE;
+  }
 
   return result;
 }
@@ -259,6 +318,12 @@ void TextVisual::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( Toolkit::TextVisual::Property::TEXT_COLOR, mController->GetDefaultColor() );
 
   map.Insert( Toolkit::TextVisual::Property::ENABLE_MARKUP, mController->IsMarkupProcessorEnabled() );
+
+  GetShadowProperties( mController, value, Text::EffectStyle::DEFAULT );
+  map.Insert( Toolkit::TextVisual::Property::SHADOW, value );
+
+  GetUnderlineProperties( mController, value, Text::EffectStyle::DEFAULT );
+  map.Insert( Toolkit::TextVisual::Property::UNDERLINE, value );
 }
 
 void TextVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
@@ -274,7 +339,9 @@ void TextVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
 TextVisual::TextVisual( VisualFactoryCache& factoryCache )
 : Visual::Base( factoryCache ),
   mController( Text::Controller::New() ),
-  mTypesetter( Text::Typesetter::New( mController->GetTextModel() ) )
+  mTypesetter( Text::Typesetter::New( mController->GetTextModel() ) ),
+  mAnimatableTextColorPropertyIndex( Property::INVALID_INDEX ),
+  mRendererUpdateNeeded( false )
 {
 }
 
@@ -313,20 +380,29 @@ void TextVisual::DoSetOnStage( Actor& actor )
   mControl = actor;
 
   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
+  Shader shader = GetTextShader(mFactoryCache, true);
 
-  Shader shader = mFactoryCache.GetShader( VisualFactoryCache::TEXT_SHADER );
-  if( ! shader )
-  {
-    shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_CLAMP );
-    shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+  mImpl->mRenderer = Renderer::New( geometry, shader );
+  mImpl->mRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, Toolkit::DepthIndex::CONTENT );
 
-    mFactoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER, shader );
+  const Vector4& defaultColor = mController->GetTextModel()->GetDefaultColor();
+  Dali::Property::Index shaderTextColorIndex = mImpl->mRenderer.RegisterProperty( "uTextColorAnimatable", defaultColor );
+
+  if ( mAnimatableTextColorPropertyIndex != Property::INVALID_INDEX )
+  {
+    // Create constraint for the animatable text's color Property with uTextColorAnimatable in the renderer.
+    if( shaderTextColorIndex != Property::INVALID_INDEX )
+    {
+      Constraint constraint = Constraint::New<Vector4>( mImpl->mRenderer, shaderTextColorIndex, EqualToConstraint() );
+      constraint.AddSource( Source( actor, mAnimatableTextColorPropertyIndex ) );
+      constraint.Apply();
+    }
   }
 
-  mImpl->mRenderer = Renderer::New( geometry, shader );
-  mImpl->mRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, Toolkit::DepthIndex::CONTENT );
+  // Renderer needs textures and to be added to control
+  mRendererUpdateNeeded = true;
 
-  UpdateRenderer( true ); // Renderer needs textures and to be added to control
+  UpdateRenderer();
 }
 
 void TextVisual::DoSetOffStage( Actor& actor )
@@ -348,7 +424,7 @@ void TextVisual::DoSetOffStage( Actor& actor )
 
 void TextVisual::OnSetTransform()
 {
-  UpdateRenderer( false );
+  UpdateRenderer();
 }
 
 void TextVisual::DoSetProperty( Dali::Property::Index index, const Dali::Property::Value& propertyValue )
@@ -423,10 +499,20 @@ void TextVisual::DoSetProperty( Dali::Property::Index index, const Dali::Propert
       }
       break;
     }
+    case Toolkit::TextVisual::Property::SHADOW:
+    {
+      SetShadowProperties( mController, propertyValue, Text::EffectStyle::DEFAULT );
+      break;
+    }
+    case Toolkit::TextVisual::Property::UNDERLINE:
+    {
+      SetUnderlineProperties( mController, propertyValue, Text::EffectStyle::DEFAULT );
+      break;
+    }
   }
 }
 
-void TextVisual::UpdateRenderer( bool initializeRendererAndTexture )
+void TextVisual::UpdateRenderer()
 {
   Actor control = mControl.GetHandle();
   if( !control )
@@ -463,8 +549,11 @@ void TextVisual::UpdateRenderer( bool initializeRendererAndTexture )
 
   const Text::Controller::UpdateTextType updateTextType = mController->Relayout( relayoutSize );
 
-  if( Text::Controller::NONE_UPDATED != ( Text::Controller::MODEL_UPDATED & updateTextType ) || initializeRendererAndTexture )
+  if( Text::Controller::NONE_UPDATED != ( Text::Controller::MODEL_UPDATED & updateTextType )
+   || mRendererUpdateNeeded )
   {
+    mRendererUpdateNeeded = false;
+
     // Removes the texture set.
     RemoveTextureSet();
 
@@ -477,39 +566,133 @@ void TextVisual::UpdateRenderer( bool initializeRendererAndTexture )
     if( ( relayoutSize.width > Math::MACHINE_EPSILON_1000 ) &&
         ( relayoutSize.height > Math::MACHINE_EPSILON_1000 ) )
     {
-      PixelData data = mTypesetter->Render( relayoutSize );
+      // Check whether it is a markup text with multiple text colors
+      const Vector4* const colorsBuffer = mController->GetTextModel()->GetColors();
+      bool hasMultipleTextColors = ( NULL != colorsBuffer );
 
-      Vector4 atlasRect = FULL_TEXTURE_RECT;
+      // Check whether the text contains any emoji
+      bool containsEmoji = false;
+
+      Text::ScriptRunIndex numberOfScripts = mController->GetTextModel()->GetNumberOfScripts();
+      const Text::ScriptRun* scripts = mController->GetTextModel()->GetScriptRuns();
+      for ( Text::ScriptRunIndex scriptIndex = 0u; scriptIndex < numberOfScripts; scriptIndex++ )
+      {
+        const Text::ScriptRun& scriptRun = *( scripts + scriptIndex );
+        if( TextAbstraction::EMOJI == scriptRun.script )
+        {
+          containsEmoji = true;
+          break;
+        }
+      }
+
+      // Check whether the text contains any style colors (e.g. underline color, shadow color, etc.)
+      bool shadowEnabled = false;
+      const Vector2& shadowOffset = mController->GetTextModel()->GetShadowOffset();
+      if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 )
+      {
+        shadowEnabled = true;
+      }
+
+      const bool underlineEnabled = mController->GetTextModel()->IsUnderlineEnabled();
+
+      if ( hasMultipleTextColors || containsEmoji || shadowEnabled || underlineEnabled )
+      {
+        // Create RGBA textures if the text contains emojis or styles or multiple text colors
+
+        // Create a texture for the text without any styles
+        PixelData data = mTypesetter->Render( relayoutSize, Text::Typesetter::RENDER_NO_STYLES );
+
+        // It may happen the image atlas can't handle a pixel data it exceeds the maximum size.
+        // In that case, create a texture. TODO: should tile the text.
+
+        Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
+                                        data.GetPixelFormat(),
+                                        data.GetWidth(),
+                                        data.GetHeight() );
+
+        texture.Upload( data );
+
+        TextureSet textureSet = TextureSet::New();
+        textureSet.SetTexture( 0u, texture );
 
-      // Texture set not retrieved from Atlas Manager whilst pixel offset visible.
+        // Create a texture for all the text styles (without the text itself)
+        PixelData styleData = mTypesetter->Render( relayoutSize, Text::Typesetter::RENDER_NO_TEXT );
 
-      // It may happen the image atlas can't handle a pixel data it exceeds the maximum size.
-      // In that case, create a texture. TODO: should tile the text.
+        Texture styleTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
+                                             styleData.GetPixelFormat(),
+                                             styleData.GetWidth(),
+                                             styleData.GetHeight() );
+
+        styleTexture.Upload( styleData );
+
+        textureSet.SetTexture( 1u, styleTexture );
+
+        // Create a texture as a mask to avoid color glyphs (e.g. emojis) to be affected by text color animation
+        PixelData maskData = mTypesetter->Render( relayoutSize, Text::Typesetter::RENDER_MASK );
+
+        Texture maskTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
+                                            styleData.GetPixelFormat(),
+                                            styleData.GetWidth(),
+                                            styleData.GetHeight() );
+
+        maskTexture.Upload( maskData );
+
+        textureSet.SetTexture( 2u, maskTexture );
+
+        // Filter mode needs to be set to nearest to produce better quality while static.
+        Sampler sampler = Sampler::New();
+        sampler.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR );
+        textureSet.SetSampler( 0u, sampler );
+        textureSet.SetSampler( 1u, sampler );
+        textureSet.SetSampler( 2u, sampler );
+
+        mImpl->mRenderer.SetTextures( textureSet );
+
+        Shader shader = GetTextShader(mFactoryCache, true); // RGBA shader
+        mImpl->mRenderer.SetShader(shader);
+      }
+      else
+      {
+        // Create L8 texture if the text contains only single text color with no emoji and no style
 
-      Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
-                                      data.GetPixelFormat(),
-                                      data.GetWidth(),
-                                      data.GetHeight() );
+        // Create a texture for the text without any styles
+        PixelData data = mTypesetter->Render( relayoutSize, Text::Typesetter::RENDER_NO_STYLES, false, Pixel::L8 );
 
-      texture.Upload( data );
+        // It may happen the image atlas can't handle a pixel data it exceeds the maximum size.
+        // In that case, create a texture. TODO: should tile the text.
 
-      TextureSet textureSet = TextureSet::New();
-      textureSet.SetTexture( 0u, texture );
+        Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
+                                        data.GetPixelFormat(),
+                                        data.GetWidth(),
+                                        data.GetHeight() );
+
+        texture.Upload( data );
+
+        TextureSet textureSet = TextureSet::New();
+        textureSet.SetTexture( 0u, texture );
+
+        // Filter mode needs to be set to nearest to produce better quality while static.
+        Sampler sampler = Sampler::New();
+        sampler.SetFilterMode( FilterMode::NEAREST, FilterMode::NEAREST );
+        textureSet.SetSampler( 0u, sampler );
+
+        mImpl->mRenderer.SetTextures( textureSet );
+
+        Shader shader = GetTextShader(mFactoryCache, false); // L8 shader
+        mImpl->mRenderer.SetShader(shader);
+      }
 
       mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
 
+      Vector4 atlasRect = FULL_TEXTURE_RECT;
       mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect );
+      mImpl->mRenderer.RegisterProperty( "uHasMultipleTextColors", static_cast<float>( hasMultipleTextColors ) );
+
+      mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON);
 
       //Register transform properties
       mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
 
-      // Filter mode needs to be set to nearest to avoid blurry text.
-      Sampler sampler = Sampler::New();
-      sampler.SetFilterMode( FilterMode::NEAREST, FilterMode::NEAREST );
-      textureSet.SetSampler( 0u, sampler );
-
-      mImpl->mRenderer.SetTextures( textureSet );
-
       control.AddRenderer( mImpl->mRenderer );
 
       // Text rendered and ready to display
@@ -537,6 +720,33 @@ void TextVisual::RemoveTextureSet()
   }
 }
 
+Shader TextVisual::GetTextShader( VisualFactoryCache& factoryCache, bool isRgbaTexture )
+{
+  Shader shader;
+  if( isRgbaTexture )
+  {
+    shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_RGBA );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_CLAMP_RGBA );
+      shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+      factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_RGBA, shader );
+    }
+  }
+  else
+  {
+    shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_L8 );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_CLAMP_L8 );
+      shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+      factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_L8, shader );
+    }
+  }
+
+  return shader;
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index 8222276..31353b9 100644 (file)
@@ -18,6 +18,9 @@
  *
  */
 
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
 #include <dali-toolkit/internal/text/rendering/text-typesetter.h>
@@ -81,6 +84,35 @@ public:
    */
   static void ConvertStringKeysToIndexKeys( Property::Map& propertyMap );
 
+  /**
+   * @brief Retrieve the text's controller.
+   * @param[in] visual The text visual.
+   * @return The text controller
+   */
+  static Text::ControllerPtr GetController( Toolkit::Visual::Base visual )
+  {
+    return GetVisualObject( visual ).mController;
+  };
+
+  /**
+   * @brief Set the index of the animatable text color property.
+   * @param[in] visual The text visual.
+   * @param[in] animatablePropertyIndex The index of the animatable property
+   */
+  static void SetAnimatableTextColorProperty( Toolkit::Visual::Base visual, Property::Index animatablePropertyIndex )
+  {
+    GetVisualObject( visual ).mAnimatableTextColorPropertyIndex = animatablePropertyIndex;
+  };
+
+  /**
+   * @brief Set the flag to trigger the textures to be initialized and renderer to be added to the control.
+   * @param[in] visual The text visual.
+   */
+  static void EnableRendererUpdate( Toolkit::Visual::Base visual )
+  {
+    GetVisualObject( visual ).mRendererUpdateNeeded = true;
+  };
+
 public: // from Visual::Base
 
   /**
@@ -151,19 +183,37 @@ private:
 
   /**
    * @brief Updates the text's renderer.
-   * @param[in] initializeRendererAndTexture Set flag to true to initialize textures and add renderer to control.
    */
-  void UpdateRenderer( bool initializeRendererAndTexture );
+  void UpdateRenderer();
 
   /**
    * @brief Removes the texture set from the renderer.
    */
   void RemoveTextureSet();
 
+  /**
+   * Get the text rendering shader.
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] isRgbaTexture Whether the texture is in RGBA format.
+   */
+  Shader GetTextShader( VisualFactoryCache& factoryCache, bool isRgbaTexture );
+
+  /**
+   * @brief Retrieve the text's controller.
+   * @param[in] visual The text visual.
+   * @return The text controller
+   */
+  static TextVisual& GetVisualObject( Toolkit::Visual::Base visual )
+  {
+    return static_cast<TextVisual&>( visual.GetBaseObject() );
+  };
+
 private:
-  Text::ControllerPtr mController; ///< The text's controller.
-  Text::TypesetterPtr mTypesetter; ///< The text's typesetter.
-  WeakHandle<Actor>   mControl;    ///< The control where the renderer is added.
+  Text::ControllerPtr mController;                        ///< The text's controller.
+  Text::TypesetterPtr mTypesetter;                        ///< The text's typesetter.
+  WeakHandle<Actor>   mControl;                           ///< The control where the renderer is added.
+  Property::Index     mAnimatableTextColorPropertyIndex;  ///< The index of animatable text color property registered by the control.
+  bool                mRendererUpdateNeeded:1;            ///< The flag to indicate whether the renderer needs to be updated.
 };
 
 } // namespace Internal
  */
 
 // CLASS HEADER
-#include "texture-manager.h"
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
 
 // EXTERNAL HEADERS
 #include <cstdlib>
+#include <string>
 #include <dali/devel-api/adaptor-framework/environment-variable.h>
 #include <dali/devel-api/common/hash.h>
 #include <dali/devel-api/images/texture-set-image.h>
@@ -85,9 +86,9 @@ const int           INVALID_CACHE_INDEX( -1 ); ///< Invalid Cache index
 
 
 TextureManager::TextureManager()
-: mCurrentTextureId( 0 ),
-  mAsyncLocalLoaders( GetNumberOfLocalLoaderThreads(), [&]() { return AsyncLoadingHelper(*this); } ),
-  mAsyncRemoteLoaders( GetNumberOfRemoteLoaderThreads(), [&]() { return AsyncLoadingHelper(*this); } )
+: mAsyncLocalLoaders( GetNumberOfLocalLoaderThreads(), [&]() { return AsyncLoadingHelper(*this); } ),
+  mAsyncRemoteLoaders( GetNumberOfRemoteLoaderThreads(), [&]() { return AsyncLoadingHelper(*this); } ),
+  mCurrentTextureId( 0 )
 {
 }
 
@@ -309,6 +310,43 @@ TextureSet TextureManager::GetTextureSet( TextureId textureId )
   return textureSet;
 }
 
+std::string TextureManager::AddExternalTexture( TextureSet& textureSet )
+{
+  TextureManager::ExternalTextureInfo info;
+  info.textureId = GenerateUniqueTextureId();
+  info.textureSet = textureSet;
+  mExternalTextures.emplace_back( info );
+  return VisualUrl::CreateTextureUrl( std::to_string( info.textureId ) );
+}
+
+TextureSet TextureManager::RemoveExternalTexture( const std::string& url )
+{
+  if( url.size() > 0u )
+  {
+    // get the location from the Url
+    VisualUrl parseUrl( url );
+    if( VisualUrl::TEXTURE == parseUrl.GetProtocolType() )
+    {
+      std::string location = parseUrl.GetLocation();
+      if( location.size() > 0u )
+      {
+        TextureId id = std::stoi( location );
+        const auto end = mExternalTextures.end();
+        for( auto iter = mExternalTextures.begin(); iter != end; ++iter )
+        {
+          if( iter->textureId == id )
+          {
+            auto textureSet = iter->textureSet;
+            mExternalTextures.erase( iter );
+            return textureSet;
+          }
+        }
+      }
+    }
+  }
+  return TextureSet();
+}
+
 bool TextureManager::LoadTexture( TextureInfo& textureInfo )
 {
   bool success = true;
@@ -319,7 +357,7 @@ bool TextureManager::LoadTexture( TextureInfo& textureInfo )
 
     if( !textureInfo.loadSynchronously )
     {
-      auto& loadersContainer = textureInfo.url.IsLocal() ? mAsyncLocalLoaders : mAsyncRemoteLoaders;
+      auto& loadersContainer = textureInfo.url.IsLocalResource() ? mAsyncLocalLoaders : mAsyncRemoteLoaders;
       auto loadingHelperIt = loadersContainer.GetNext();
       DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End());
       loadingHelperIt->Load(textureInfo.textureId, textureInfo.url,
@@ -1,5 +1,5 @@
-#ifndef DALI_TOOLKIT_TEXTURE_MANAGER_H
-#define DALI_TOOLKIT_TEXTURE_MANAGER_H
+#ifndef DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H
+#define DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H
 
 /*
  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
@@ -46,8 +46,6 @@ namespace Toolkit
 namespace Internal
 {
 
-class MaskTextureObserver;
-
 /**
  * The TextureManager provides a common Image loading API for Visuals.
  *
@@ -212,6 +210,20 @@ public:
    */
   TextureSet GetTextureSet( TextureId textureId );
 
+  /**
+   * Adds an external texture to the texture manager
+   * @param[in] texture The texture to add
+   * @return string containing the URL for the texture
+   */
+  std::string AddExternalTexture( TextureSet& texture );
+
+  /**
+   * Removes an external texture from texture manager
+   * @param[in] url The string containing the texture to remove
+   * @return handle to the texture
+   */
+  TextureSet RemoveExternalTexture( const std::string& url );
+
 private:
 
   /**
@@ -547,6 +559,12 @@ private:
     AsyncLoadingInfoContainerType mLoadingInfoContainer;
   };
 
+  struct ExternalTextureInfo
+  {
+    TextureId textureId;
+    TextureSet textureSet;
+  };
+
 private:
 
   /**
@@ -568,12 +586,13 @@ private:
 
 private:  // Member Variables:
 
-  AtlasInfoContainerType        mAtlasContainer;                  ///< Used to manage Atlas creation and destruction
-  TextureInfoContainerType      mTextureInfoContainer;            ///< Used to manage the life-cycle and caching of Textures
-  TextureId                     mCurrentTextureId;                ///< The current value used for the unique Texture Id generation
+  AtlasInfoContainerType                        mAtlasContainer;       ///< Used to manage Atlas creation and destruction
+  TextureInfoContainerType                      mTextureInfoContainer; ///< Used to manage the life-cycle and caching of Textures
+  RoundRobinContainerView< AsyncLoadingHelper > mAsyncLocalLoaders;    ///< The Asynchronous image loaders used to provide all local async loads
+  RoundRobinContainerView< AsyncLoadingHelper > mAsyncRemoteLoaders;   ///< The Asynchronous image loaders used to provide all remote async loads
+  std::vector< ExternalTextureInfo >            mExternalTextures;     ///< Externally provided textures
+  TextureId                                     mCurrentTextureId;     ///< The current value used for the unique Texture Id generation
 
-  RoundRobinContainerView<AsyncLoadingHelper> mAsyncLocalLoaders;  ///< The Asynchronous image loaders used to provide all local async loads
-  RoundRobinContainerView<AsyncLoadingHelper> mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads
 };
 
 
@@ -583,4 +602,4 @@ private:  // Member Variables:
 
 } // namespace Dali
 
-#endif // DALI_TOOLKIT_TEXTURE_MANAGER_H
+#endif // DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H
index cc68e0f..aac15c7 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_VISUAL_FACTORY_CACHE_H
 
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/visuals/npatch-loader.h>
 #include <dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h>
-#include <dali-toolkit/internal/visuals/texture-manager.h>
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
 
 namespace Dali
 {
@@ -69,7 +69,8 @@ public:
     IMAGE_SHADER_ATLAS_CUSTOM_WRAP,
     NINE_PATCH_SHADER,
     SVG_SHADER,
-    TEXT_SHADER,
+    TEXT_SHADER_RGBA,
+    TEXT_SHADER_L8,
     WIREFRAME_SHADER,
     SHADER_TYPE_MAX = WIREFRAME_SHADER
   };
index 469ead5..3aef5bc 100644 (file)
@@ -1,5 +1,5 @@
  /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -316,6 +316,15 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const std::string& url, Image
   return Toolkit::Visual::Base( visualPtr.Get() );
 }
 
+Internal::TextureManager& VisualFactory::GetTextureManager()
+{
+  if( !mFactoryCache )
+  {
+    mFactoryCache = new VisualFactoryCache();
+  }
+  return mFactoryCache->GetTextureManager();
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index 030512e..257b03c 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_VISUAL_FACTORY_IMPL_H
 
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -66,6 +66,11 @@ public:
    */
   Toolkit::Visual::Base CreateVisual( const std::string& image, ImageDimensions size );
 
+  /**
+   * @return the reference to texture manager
+   */
+  Internal::TextureManager& GetTextureManager();
+
 protected:
 
   /**
index c3c675d..907b428 100644 (file)
@@ -30,54 +30,59 @@ namespace Internal
 namespace
 {
 
-VisualUrl::Location ResolveLocation( const std::string& url)
+VisualUrl::ProtocolType ResolveLocation( const std::string& url )
 {
-  const char FTP[] = { 'f', 't', 'p', ':', '/', '/' };
-  const char SSH[] = { 's', 's', 'h', ':', '/', '/' };
-  const char HTTP[] = { 'h', 't', 't', 'p', ':', '/', '/' };
-  const char HTTPS[] = { 'h', 't', 't', 'p', 's', ':', '/', '/' };
-
-  const int MATCH_FTP = 0x01;
-  const int MATCH_SSH = 0x02;
-  const int MATCH_HTTP = 0x04;
-  const int MATCH_HTTPS = 0x08;
-
   const char* urlCStr = url.c_str();
-  if( url.size() > 6 )
+  const uint32_t length = url.size();
+  if( ( length > 7 ) && urlCStr[5] == ':' && urlCStr[6] == '/' && urlCStr[7] == '/' )
+  {
+    // https://
+    if( ( 'h' == tolower( urlCStr[0] ) )&&
+        ( 't' == tolower( urlCStr[1] ) )&&
+        ( 't' == tolower( urlCStr[2] ) )&&
+        ( 'p' == tolower( urlCStr[3] ) )&&
+        ( 's' == tolower( urlCStr[4] ) ) )
+    {
+      return VisualUrl::REMOTE;
+    }
+  }
+  else if( ( length > 6 ) && urlCStr[4] == ':' && urlCStr[5] == '/' && urlCStr[6] == '/' )
+  {
+    // http:// or dali://
+    const char hOrd = tolower( urlCStr[0] );
+    const char tOra = tolower( urlCStr[1] );
+    const char tOrl = tolower( urlCStr[2] );
+    const char pOri = tolower( urlCStr[3] );
+    if( ( 'h' == hOrd )&&
+        ( 't' == tOra )&&
+        ( 't' == tOrl )&&
+        ( 'p' == pOri ) )
+    {
+      return VisualUrl::REMOTE;
+    }
+    if( ( 'd' == hOrd )&&
+        ( 'a' == tOra )&&
+        ( 'l' == tOrl )&&
+        ( 'i' == pOri ) )
+    {
+      return VisualUrl::TEXTURE;
+    }
+  }
+  else if( ( length > 5 ) && urlCStr[3] == ':' && urlCStr[4] == '/' && urlCStr[5] == '/' )
   {
-    if( urlCStr[3] == ':' || urlCStr[4] == ':' || urlCStr[5] == ':' )
+    // ftp:// or ssh://
+    const char fOrS = tolower( urlCStr[0] );
+    if( ( 'f' == fOrS )||( 's' == fOrS ) )
     {
-      int flags = 0x0F;
-      for( unsigned int i=0; i < sizeof(HTTPS); ++i )
+      const char tOrs = tolower( urlCStr[1] );
+      if( ( 't' == tOrs )||( 's' == tOrs ) )
       {
-        char c = tolower( urlCStr[i] );
-        if( i < sizeof(FTP) && (flags & MATCH_FTP) && c != FTP[i] )
-        {
-          flags &= ~MATCH_FTP;
-        }
-        if( i < sizeof(SSH) && (flags & MATCH_SSH) && c != SSH[i] )
-        {
-          flags &= ~MATCH_SSH;
-        }
-        if( i < sizeof(HTTP) && (flags & MATCH_HTTP) && c != HTTP[i] )
-        {
-          flags &= ~MATCH_HTTP;
-        }
-        if( i < sizeof(HTTPS) && (flags & MATCH_HTTPS) && c != HTTPS[i] )
+        const char pOrh = tolower( urlCStr[2] );
+        if( ( 'p' == pOrh )||( 'h' == pOrh ) )
         {
-          flags &= ~MATCH_HTTPS;
-        }
-
-        if( (flags & (MATCH_FTP | MATCH_SSH | MATCH_HTTP | MATCH_HTTPS )) == 0 )
-        {
-          break;
+          return VisualUrl::REMOTE;
         }
       }
-
-      if( flags )
-      {
-        return VisualUrl::REMOTE;
-      }
     }
   }
   return VisualUrl::LOCAL;
@@ -99,9 +104,9 @@ VisualUrl::Type ResolveType( const std::string& url )
     int index = count;
     while( --index >= 0 )
     {
-      const char currentChar = url[ index ];
+      const char currentChar = tolower( url[ index ] );
       const std::size_t offsetFromEnd = count - index - 1u;
-      if( ( offsetFromEnd < sizeof(SVG) )&&( tolower( currentChar ) == SVG[ offsetFromEnd ] ) )
+      if( ( offsetFromEnd < sizeof(SVG) )&&( currentChar == SVG[ offsetFromEnd ] ) )
       {
         // early out if SVG as can't be used in N patch for now
         if( ++svgScore == sizeof(SVG) )
@@ -109,9 +114,9 @@ VisualUrl::Type ResolveType( const std::string& url )
           return VisualUrl::SVG;
         }
       }
-      if( ( offsetFromEnd < sizeof(GIF) )&&( tolower( currentChar ) == GIF[ offsetFromEnd ] ) )
+      if( ( offsetFromEnd < sizeof(GIF) )&&( currentChar == GIF[ offsetFromEnd ] ) )
       {
-        // early out if GIF
+        // early out if GIF as can't be used in N patch for now
         if( ++gifScore == sizeof(GIF) )
         {
           return VisualUrl::GIF;
@@ -178,7 +183,11 @@ VisualUrl::VisualUrl( const std::string& url )
   if( ! url.empty() )
   {
     mLocation = ResolveLocation( url );
-    mType = ResolveType( url );
+    if( VisualUrl::TEXTURE != mLocation )
+    {
+      // TEXTURE location url doesn't need type resolving, REGULAR_IMAGE is fine
+      mType = ResolveType( url );
+    }
   }
 }
 
@@ -210,7 +219,7 @@ VisualUrl::Type VisualUrl::GetType() const
   return mType;
 }
 
-VisualUrl::Location VisualUrl::GetLocation() const
+VisualUrl::ProtocolType VisualUrl::GetProtocolType() const
 {
   return mLocation;
 }
@@ -220,13 +229,28 @@ bool VisualUrl::IsValid() const
   return mUrl.size() > 0u;
 }
 
-bool VisualUrl::IsLocal() const
+bool VisualUrl::IsLocalResource() const
 {
   return mLocation == VisualUrl::LOCAL;
 }
 
+std::string VisualUrl::GetLocation()
+{
+  const auto location = mUrl.find( "://" );
+  if( std::string::npos != location )
+  {
+    return mUrl.substr( location + 3u ); // 3 characters forwards from the start of ://
+  }
+  return mUrl;
+}
 
+std::string VisualUrl::CreateTextureUrl( const std::string& location )
+{
+  return "dali://" + location;
+}
 
 } // Internal
+
 } // Toolkit
+
 } // Dali
index d9ed48a..b261813 100644 (file)
@@ -43,10 +43,11 @@ public:
     GIF
   };
 
-  enum Location
+  enum ProtocolType
   {
-    LOCAL,
-    REMOTE
+    LOCAL,   ///< file in local file system
+    TEXTURE, ///< texture uploaded to texture manager
+    REMOTE   ///< remote image
   };
 
   /**
@@ -90,7 +91,7 @@ public:
    * Is the URL is local to the device, or remote?
    * @return the location of the resource
    */
-  Location GetLocation() const;
+  ProtocolType GetProtocolType() const;
 
   /**
    * Is the URL valid?
@@ -99,14 +100,26 @@ public:
   bool IsValid() const;
 
   /**
-   * @return true if the location is LOCAL
+   * @return true if the location is LOCAL, i.e. is loadable from local file system
    */
-  bool IsLocal() const;
+  bool IsLocalResource() const;
+
+  /**
+   * @return the location part of the url
+   */
+  std::string GetLocation();
+
+  /**
+   * Helper to create a URL of type TEXTURE
+   * @param location the location of the texture
+   * @return the Url
+   */
+  static std::string CreateTextureUrl( const std::string& location );
 
 private:
   std::string mUrl;
   Type mType;
-  Location mLocation;
+  ProtocolType mLocation;
 };
 
 
index 5674716..df0abce 100644 (file)
@@ -90,6 +90,7 @@ public:
     enum
     {
       /**
+       * DEPRECATED_1_2.53 No longer be supported and will be ignored.
        * @brief The type of rendering e.g. bitmap-based.
        * @details name "renderingBackend", type INT, default RENDERING_SHARED_ATLAS.
        * @SINCE_1_0.0
index 8417ead..cc78eff 100644 (file)
@@ -31,7 +31,7 @@ namespace Toolkit
 
 const unsigned int TOOLKIT_MAJOR_VERSION = 1;
 const unsigned int TOOLKIT_MINOR_VERSION = 2;
-const unsigned int TOOLKIT_MICRO_VERSION = 56;
+const unsigned int TOOLKIT_MICRO_VERSION = 57;
 const char * const TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED