From df8ef77e426a89443795efe8e6203646755b3631 Mon Sep 17 00:00:00 2001 From: David Steele Date: Wed, 15 Mar 2017 13:25:58 +0000 Subject: [PATCH] Encapsulated visual URL in new VisualUrl class. The VisualUrl object encapsulates the URL string and also resolves the data type and whether the url is local or remote on creation. Change-Id: I88cfc98563799d2646bde1911a5e8e90496ffd45 Signed-off-by: David Steele Conflicts: automated-tests/src/dali-toolkit-internal/CMakeLists.txt automated-tests/src/dali-toolkit/utc-Dali-PushButton.cpp dali-toolkit/internal/file.list dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp dali-toolkit/internal/visuals/animated-image/animated-image-visual.h dali-toolkit/internal/visuals/image/image-visual.cpp dali-toolkit/internal/visuals/image/image-visual.h dali-toolkit/internal/visuals/npatch/npatch-visual.cpp dali-toolkit/internal/visuals/npatch/npatch-visual.h dali-toolkit/internal/visuals/svg/svg-visual.cpp dali-toolkit/internal/visuals/svg/svg-visual.h dali-toolkit/internal/visuals/visual-factory-impl.cpp --- .../src/dali-toolkit-internal/CMakeLists.txt | 8 + .../dali-toolkit-internal/utc-Dali-VisualUrl.cpp | 307 +++++++++++++++++++++ .../src/dali-toolkit/utc-Dali-PushButton.cpp | 61 +++- dali-toolkit/internal/file.list | 21 +- .../animated-image/animated-image-visual.cpp | 256 +++++++++++++++++ .../visuals/animated-image/animated-image-visual.h | 180 ++++++++++++ .../internal/visuals/image/image-visual.cpp | 181 +++++++----- dali-toolkit/internal/visuals/image/image-visual.h | 77 +++++- .../internal/visuals/npatch/npatch-visual.cpp | 66 ++++- .../internal/visuals/npatch/npatch-visual.h | 39 ++- dali-toolkit/internal/visuals/svg/svg-visual.cpp | 52 ++-- dali-toolkit/internal/visuals/svg/svg-visual.h | 18 +- .../internal/visuals/visual-factory-impl.cpp | 81 +++--- dali-toolkit/internal/visuals/visual-url.cpp | 232 ++++++++++++++++ dali-toolkit/internal/visuals/visual-url.h | 119 ++++++++ 15 files changed, 1538 insertions(+), 160 deletions(-) create mode 100644 automated-tests/src/dali-toolkit-internal/utc-Dali-VisualUrl.cpp create mode 100644 dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp create mode 100644 dali-toolkit/internal/visuals/animated-image/animated-image-visual.h create mode 100644 dali-toolkit/internal/visuals/visual-url.cpp create mode 100644 dali-toolkit/internal/visuals/visual-url.h diff --git a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt index 0feca8b..dcb77e3 100644 --- a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt @@ -18,6 +18,14 @@ SET(TC_SOURCES utc-Dali-VisualModel.cpp utc-Dali-Text-Layout.cpp utc-Dali-Text-Controller.cpp + + utc-Dali-VisualUrl.cpp + utc-Dali-Text-Markup.cpp + utc-Dali-Text-Typesetter.cpp + utc-Dali-Text-ViewModel.cpp + utc-Dali-DebugRendering.cpp + utc-Dali-ItemView-internal.cpp + utc-Dali-PropertyHelper.cpp utc-Dali-ColorConversion.cpp ) diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualUrl.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualUrl.cpp new file mode 100644 index 0000000..476a023 --- /dev/null +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualUrl.cpp @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +#include + +#include +#include + +using namespace Dali::Toolkit::Internal; + +int UtcDaliVisualUrlConstructor(void) +{ + const char* url="http://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 ); + + 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 ); + + 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 ); + END_TEST; +} + + +int UtcDaliVisualUrlRegularImage(void) +{ + tet_infoline( "UtcDaliVisualUrl REGULAR_IMAGE" ); + + DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("foobar.jpeg").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("foobar.PNG").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("foobar.Png123").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("foobar.Png1.23").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl(" ").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl(".").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("9").GetType(), TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliVisualUrlSvg(void) +{ + tet_infoline( "UtcDaliVisualUrl SVG" ); + + DALI_TEST_EQUALS( VisualUrl::SVG, VisualUrl("foobar.svg").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::SVG, VisualUrl("foobar.svg.svg").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::SVG, VisualUrl("foobar.svG").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::SVG, VisualUrl("foobar.SVG").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::SVG, VisualUrl(".SvG").GetType(), TEST_LOCATION ); + + // SVGs aren't N-patch + DALI_TEST_EQUALS( VisualUrl::SVG, VisualUrl("foobar.9.svg").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("svg.png").GetType(), TEST_LOCATION ); + + // maybe controversial, but for now we expect the suffix to be exactly .svg + DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("svg.svg1").GetType(), TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliVisualUrlNPatch(void) +{ + tet_infoline( "UtcDaliVisualUrl N_PATCH" ); + + DALI_TEST_EQUALS( VisualUrl::N_PATCH, VisualUrl("foobar.#.png").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::N_PATCH, VisualUrl("foobar.9.9.bmp").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::N_PATCH, VisualUrl("foobar.9.9.jpg[]=$$").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::N_PATCH, VisualUrl("foobar.9.#.#.9.wbpm123").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("svg.##.png").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("svg.99.jpeg").GetType(), TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliVisualUrlGif(void) +{ + tet_infoline( "UtcDaliVisualUrl GIF" ); + + DALI_TEST_EQUALS( VisualUrl::GIF, VisualUrl("foobar.gif").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::GIF, VisualUrl("foobar.gif.gif").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::GIF, VisualUrl("foobar.giF").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::GIF, VisualUrl("foobar.GIF").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::GIF, VisualUrl(".GiF").GetType(), TEST_LOCATION ); + + // GIFs aren't N-patch + DALI_TEST_EQUALS( VisualUrl::GIF, VisualUrl("foobar.9.gif").GetType(), TEST_LOCATION ); + + DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("gif.png").GetType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("gif.gif1").GetType(), TEST_LOCATION ); + + END_TEST; +} + + +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 ); + + END_TEST; +} + + +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 ); + + END_TEST; +} + + +int UtcDaliVisualUrlIsValid(void) +{ + tet_infoline( "UtcDaliVisualUrl IsValid" ); + + DALI_TEST_EQUALS( false, VisualUrl().IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( false, VisualUrl("").IsValid(), TEST_LOCATION ); + + DALI_TEST_EQUALS( true, VisualUrl("foobar.gif").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("foobar.png").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("foobar.svg").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("foobar.GIF").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("foobar.9.png").IsValid(), TEST_LOCATION ); + + DALI_TEST_EQUALS( true, VisualUrl("http://bar.org/foobar.gif").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("http://bar.org/foobar.png").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("http://bar.org/foobar.svg").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("http://bar.org/foobar.GIF").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("http://bar.org/foobar.9.png").IsValid(), TEST_LOCATION ); + + DALI_TEST_EQUALS( true, VisualUrl("https://bar.org/foobar.gif").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("https://bar.org/foobar.png").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("https://bar.org/foobar.svg").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("https://bar.org/foobar.GIF").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("https://bar.org/foobar.9.png").IsValid(), TEST_LOCATION ); + + DALI_TEST_EQUALS( true, VisualUrl("HTTP://bar.org/foobar.gif").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("HTTP://bar.org/foobar.png").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("HTTP://bar.org/foobar.svg").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("HTTP://bar.org/foobar.GIF").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("HTTP://bar.org/foobar.9.png").IsValid(), TEST_LOCATION ); + + DALI_TEST_EQUALS( true, VisualUrl("HTTPS://bar.org/foobar.gif").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("HTTPS://bar.org/foobar.png").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("HTTPS://bar.org/foobar.svg").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("HTTPS://bar.org/foobar.GIF").IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, VisualUrl("HTTPS://bar.org/foobar.9.png").IsValid(), TEST_LOCATION ); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit/utc-Dali-PushButton.cpp b/automated-tests/src/dali-toolkit/utc-Dali-PushButton.cpp index a191f43..074e0f3 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-PushButton.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-PushButton.cpp @@ -26,6 +26,12 @@ #include #include +#include +#include +#include + +#include + using namespace Dali; using namespace Toolkit; @@ -661,8 +667,13 @@ int UtcDaliPushButtonPaddingLayout(void) // The icon and label are each enabled and disabled to confirm the correct padding is used. PushButton pushButton = PushButton::New(); - pushButton.SetProperty( Toolkit::PushButton::Property::LABEL_PADDING, Vector4( 10.0f, 10.0f, 10.0f, 10.0f ) ); - pushButton.SetProperty( Toolkit::PushButton::Property::ICON_PADDING, Vector4( 20.0f, 20.0f, 20.0f, 20.0f ) ); + + const Vector4 TEST_ICON_PADDING( 20.0f, 20.0f, 20.0f, 20.0f ); + const Vector4 TEST_LABEL_PADDING( 10.0f, 10.0f, 10.0f, 10.0f ); + + // Get actual size of test image + ImageDimensions testImageSize = Dali::GetClosestImageSize( TEST_IMAGE_ONE ); + const Vector2 TEST_IMAGE_SIZE( testImageSize.GetWidth(), testImageSize.GetHeight() ); pushButton.SetAnchorPoint( AnchorPoint::TOP_LEFT ); pushButton.SetParentOrigin( ParentOrigin::TOP_LEFT ); @@ -709,7 +720,8 @@ int UtcDaliPushButtonPaddingLayout(void) Stage::GetCurrent().Add( pushButton ); - const char* INVALID_IMAGE_FILE_NAME = "invalid-image.jpg"; + + pushButton.SetProperty( Toolkit::PushButton::Property::ICON_ALIGNMENT, "RIGHT" ); pushButton.SetProperty( Toolkit::PushButton::Property::UNSELECTED_ICON, INVALID_IMAGE_FILE_NAME ); pushButton.SetProperty( Toolkit::PushButton::Property::SELECTED_ICON, INVALID_IMAGE_FILE_NAME ); @@ -720,7 +732,18 @@ int UtcDaliPushButtonPaddingLayout(void) size.width = pushButton.GetRelayoutSize( Dimension::WIDTH ); size.height = pushButton.GetRelayoutSize( Dimension::HEIGHT ); - DALI_TEST_EQUALS( size, Vector2( 40.0f, 40.0f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + + pushButton.SetProperty( Toolkit::PushButton::Property::ICON_PADDING, TEST_ICON_PADDING ); + + application.SendNotification(); + application.Render(); + DALI_TEST_EQUALS( size, TEST_IMAGE_SIZE, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + + size.width = pushButton.GetRelayoutSize( Dimension::WIDTH ); + size.height = pushButton.GetRelayoutSize( Dimension::HEIGHT ); + tet_printf( "Button RelayoutSize after icon padding(%f,%f)\n", size.width, size.height ); + const Vector2 expectedIconAndPaddingSize( TEST_ICON_PADDING.x+TEST_ICON_PADDING.y+TEST_IMAGE_SIZE.width, TEST_ICON_PADDING.w + TEST_ICON_PADDING.z + TEST_IMAGE_SIZE.height ); + DALI_TEST_EQUALS( size, expectedIconAndPaddingSize, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); // Now test padding for both label and icon simultaneously. pushButton.SetLabelText( "Label" ); @@ -731,10 +754,10 @@ int UtcDaliPushButtonPaddingLayout(void) size.width = pushButton.GetRelayoutSize( Dimension::WIDTH ); size.height = pushButton.GetRelayoutSize( Dimension::HEIGHT ); - // We should not test against the exact label size, we just make sure it is larger than our label padding so we know the padding has been applied. - // Note we only test the width as we are horizontally aligned and the label my be less high than the icon. - // Full directional alignment tests are done in UtcDaliPushButtonAlignmentLayout. - DALI_TEST_GREATER( size.width, 60.0f, TEST_LOCATION ); + + DALI_TEST_EQUALS( size.width, sizeLabelAndPadding.width + expectedIconAndPaddingSize.width, TEST_LOCATION ); + // Test height of control is same as icon and padding, as Text is smaller than icon + DALI_TEST_EQUALS( size.height, expectedIconAndPaddingSize.height, TEST_LOCATION ); END_TEST; } @@ -769,6 +792,15 @@ int UtcDaliPushButtonAlignmentLayout(void) * | | v +------------+ - * +---------+ - */ + + + const Vector4 TEST_ICON_PADDING( 70.0f, 70.0f, 70.0f, 70.0f ); + const Vector4 TEST_LABEL_PADDING( 30.0f, 30.0f, 30.0f, 30.0f ); + + // Get actual size of test image + ImageDimensions testImageSize = Dali::GetClosestImageSize( TEST_IMAGE_ONE ); + const Vector2 TEST_IMAGE_SIZE( testImageSize.GetWidth(), testImageSize.GetHeight() ); + PushButton pushButton = PushButton::New(); pushButton.SetProperty( Toolkit::PushButton::Property::LABEL_PADDING, Vector4( 30.0f, 30.0f, 30.0f, 30.0f ) ); @@ -796,8 +828,17 @@ int UtcDaliPushButtonAlignmentLayout(void) DALI_TEST_EQUALS( baseSize, Vector2( 150.0f, 150.0f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION ); - // Add a label to cause size to be modified in the direction of alignment. - pushButton.SetLabelText( "Label" ); + + DALI_TEST_EQUALS( labelAndPaddingSize, expectedLabelAndPaddingSize , Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + + const Vector2 testImageWithPaddingSize = Vector2 ( ( TEST_IMAGE_SIZE.width + TEST_ICON_PADDING.x + TEST_ICON_PADDING.y ), + ( TEST_IMAGE_SIZE.height + TEST_ICON_PADDING.w + TEST_ICON_PADDING.z ) ); + + // Add Icon and set its alignment + pushButton.SetProperty( Toolkit::PushButton::Property::ICON_ALIGNMENT, "RIGHT" ); + pushButton.SetProperty( Toolkit::PushButton::Property::UNSELECTED_ICON, TEST_IMAGE_ONE ); + pushButton.SetProperty( Toolkit::PushButton::Property::SELECTED_ICON, TEST_IMAGE_ONE ); + pushButton.SetProperty( Toolkit::PushButton::Property::ICON_PADDING, TEST_ICON_PADDING ); application.SendNotification(); application.Render(); diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 3488b4c..33dc9b7 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -10,24 +10,31 @@ toolkit_src_files = \ $(toolkit_src_dir)/builder/json-parser-impl.cpp \ $(toolkit_src_dir)/builder/tree-node-manipulator.cpp \ $(toolkit_src_dir)/builder/replacement.cpp \ - $(toolkit_src_dir)/visuals/visual-base-impl.cpp \ - $(toolkit_src_dir)/visuals/visual-base-data-impl.cpp \ - $(toolkit_src_dir)/visuals/image-atlas-manager.cpp \ - $(toolkit_src_dir)/visuals/visual-factory-cache.cpp \ - $(toolkit_src_dir)/visuals/visual-factory-impl.cpp \ - $(toolkit_src_dir)/visuals/visual-string-constants.cpp \ + + $(toolkit_src_dir)/visuals/animated-image/animated-image-visual.cpp \ $(toolkit_src_dir)/visuals/border/border-visual.cpp \ $(toolkit_src_dir)/visuals/color/color-visual.cpp \ + $(toolkit_src_dir)/visuals/gradient/gradient-visual.cpp \ $(toolkit_src_dir)/visuals/gradient/gradient.cpp \ $(toolkit_src_dir)/visuals/gradient/linear-gradient.cpp \ $(toolkit_src_dir)/visuals/gradient/radial-gradient.cpp \ - $(toolkit_src_dir)/visuals/gradient/gradient-visual.cpp \ + $(toolkit_src_dir)/visuals/image-atlas-manager.cpp \ $(toolkit_src_dir)/visuals/image/image-visual.cpp \ $(toolkit_src_dir)/visuals/mesh/mesh-visual.cpp \ + $(toolkit_src_dir)/visuals/npatch-loader.cpp \ $(toolkit_src_dir)/visuals/npatch/npatch-visual.cpp \ $(toolkit_src_dir)/visuals/primitive/primitive-visual.cpp \ $(toolkit_src_dir)/visuals/svg/svg-rasterize-thread.cpp \ $(toolkit_src_dir)/visuals/svg/svg-visual.cpp \ + + $(toolkit_src_dir)/visuals/text/text-visual.cpp \ + $(toolkit_src_dir)/visuals/transition-data-impl.cpp \ + $(toolkit_src_dir)/visuals/visual-base-data-impl.cpp \ + $(toolkit_src_dir)/visuals/visual-base-impl.cpp \ + $(toolkit_src_dir)/visuals/visual-factory-cache.cpp \ + $(toolkit_src_dir)/visuals/visual-factory-impl.cpp \ + $(toolkit_src_dir)/visuals/visual-string-constants.cpp \ + $(toolkit_src_dir)/visuals/visual-url.cpp \ $(toolkit_src_dir)/visuals/wireframe/wireframe-visual.cpp \ $(toolkit_src_dir)/controls/alignment/alignment-impl.cpp \ $(toolkit_src_dir)/controls/bloom-view/bloom-view-impl.cpp \ diff --git a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp new file mode 100644 index 0000000..217994e --- /dev/null +++ b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include "animated-image-visual.h" + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +namespace +{ +// wrap modes +DALI_ENUM_TO_STRING_TABLE_BEGIN( WRAP_MODE ) +DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, DEFAULT ) +DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, CLAMP_TO_EDGE ) +DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, REPEAT ) +DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, MIRRORED_REPEAT ) +DALI_ENUM_TO_STRING_TABLE_END( WRAP_MODE ) + +const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f); + +} + +AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl, const Property::Map& properties ) +{ + AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache ); + visual->mImageUrl = imageUrl; + visual->SetProperties( properties ); + + return visual; +} + +AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl ) +{ + AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache ); + visual->mImageUrl = imageUrl; + + return visual; +} + +AnimatedImageVisual::AnimatedImageVisual( VisualFactoryCache& factoryCache ) +: Visual::Base( factoryCache ), + mFrameDelayTimer(), + mPixelArea( FULL_TEXTURE_RECT ), + mImageUrl(), + mImageSize(), + mCurrentFrameIndex( 0 ), + mWrapModeU( WrapMode::DEFAULT ), + mWrapModeV( WrapMode::DEFAULT ) +{} + +AnimatedImageVisual::~AnimatedImageVisual() +{ +} + +void AnimatedImageVisual::GetNaturalSize( Vector2& naturalSize ) +{ + if( mImageSize.GetWidth() == 0 && mImageSize.GetHeight() == 0) + { + mImageSize = Dali::GetGifImageSize( mImageUrl.GetUrl() ); + } + + naturalSize.width = mImageSize.GetWidth(); + naturalSize.height = mImageSize.GetHeight(); +} + +void AnimatedImageVisual::DoCreatePropertyMap( Property::Map& map ) const +{ + map.Clear(); + + map.Insert( Toolkit::DevelVisual::Property::TYPE, Toolkit::DevelVisual::ANIMATED_IMAGE ); + + if( mImageUrl.IsValid() ) + { + map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl() ); + } + + map.Insert( Toolkit::ImageVisual::Property::PIXEL_AREA, mPixelArea ); + map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_U, mWrapModeU ); + map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV ); +} + +void AnimatedImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const +{ + // Do nothing +} + +void AnimatedImageVisual::DoSetProperties( const Property::Map& propertyMap ) +{ + // url already passed in from constructor + + Property::Value* pixelAreaValue = propertyMap.Find( Toolkit::ImageVisual::Property::PIXEL_AREA, PIXEL_AREA_UNIFORM_NAME ); + if( pixelAreaValue ) + { + pixelAreaValue->Get( mPixelArea ); + } + + Property::Value* wrapModeValueU = propertyMap.Find( Toolkit::ImageVisual::Property::WRAP_MODE_U, IMAGE_WRAP_MODE_U ); + if( wrapModeValueU ) + { + int value; + Scripting::GetEnumerationProperty( *wrapModeValueU, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, value ); + mWrapModeU = Dali::WrapMode::Type( value ); + } + + Property::Value* wrapModeValueV = propertyMap.Find( Toolkit::ImageVisual::Property::WRAP_MODE_V, IMAGE_WRAP_MODE_V ); + if( wrapModeValueV ) + { + int value; + Scripting::GetEnumerationProperty( *wrapModeValueV, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, value ); + mWrapModeV = Dali::WrapMode::Type( value ); + } +} + +void AnimatedImageVisual::DoSetOnStage( Actor& actor ) +{ + Texture texture = PrepareAnimatedImage(); + if( texture ) // if the image loading is successful + { + bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE; + Shader shader = ImageVisual::GetImageShader( mFactoryCache, true, defaultWrapMode ); + + Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY ); + + TextureSet textureSet = TextureSet::New(); + textureSet.SetTexture( 0u, texture ); + + mImpl->mRenderer = Renderer::New( geometry, shader ); + mImpl->mRenderer.SetTextures( textureSet ); + + // Register transform properties + mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT ); + + if( !defaultWrapMode ) // custom wrap mode + { + Vector2 wrapMode(mWrapModeU-WrapMode::CLAMP_TO_EDGE, mWrapModeV-WrapMode::CLAMP_TO_EDGE); + wrapMode.Clamp( Vector2::ZERO, Vector2( 2.f, 2.f ) ); + mImpl->mRenderer.RegisterProperty( WRAP_MODE_UNIFORM_NAME, wrapMode ); + } + + if( mPixelArea != FULL_TEXTURE_RECT ) + { + mImpl->mRenderer.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, mPixelArea ); + } + + mCurrentFrameIndex = 0; + mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mTextureRectContainer[mCurrentFrameIndex] ); + if( mFrameDelayContainer.Count() > 1 ) + { + mFrameDelayTimer = Timer::New( mFrameDelayContainer[0] ); + mFrameDelayTimer.TickSignal().Connect( this, &AnimatedImageVisual::DisplayNextFrame ); + mFrameDelayTimer.Start(); + } + + actor.AddRenderer( mImpl->mRenderer ); + } +} + +void AnimatedImageVisual::DoSetOffStage( Actor& actor ) +{ + if( !mImpl->mRenderer ) + { + return; + } + + if( mFrameDelayTimer ) + { + mFrameDelayTimer.Stop(); + mFrameDelayTimer.Reset(); + } + + mTextureRectContainer.Clear(); + mFrameDelayContainer.Clear(); + + actor.RemoveRenderer( mImpl->mRenderer ); + mImpl->mRenderer.Reset(); +} + +void AnimatedImageVisual::OnSetTransform() +{ + if( mImpl->mRenderer ) + { + mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT ); + } +} + +Texture AnimatedImageVisual::PrepareAnimatedImage() +{ + // load from image file + std::vector pixelDataList; + + if( mImageUrl.IsLocal() ) + { + if( Dali::LoadAnimatedGifFromFile( mImageUrl.GetUrl().c_str() , pixelDataList, mFrameDelayContainer ) ) + { + mImageSize.SetWidth( pixelDataList[0].GetWidth() ); + mImageSize.SetHeight( pixelDataList[0].GetHeight() ); + + return Toolkit::ImageAtlas::PackToAtlas( pixelDataList, mTextureRectContainer ); + } + } + + return Texture(); +} + +bool AnimatedImageVisual::DisplayNextFrame() +{ + mCurrentFrameIndex = (mCurrentFrameIndex+1) % mFrameDelayContainer.Count(); + mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mTextureRectContainer[mCurrentFrameIndex] ); + if( mFrameDelayTimer.GetInterval() != mFrameDelayContainer[mCurrentFrameIndex] ) + { + mFrameDelayTimer.SetInterval( mFrameDelayContainer[mCurrentFrameIndex] ); + } + + return true; +} + + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h new file mode 100644 index 0000000..4e11cce --- /dev/null +++ b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h @@ -0,0 +1,180 @@ +#ifndef DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H +#define DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H + +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +class AnimatedImageVisual; +typedef IntrusivePtr< AnimatedImageVisual > AnimatedImageVisualPtr; + +/** + * The visual which renders an animated image + * + * The following property is essential + * + * | %Property Name | Type | + * |------------------- |-------------------| + * | url | STRING | + * | pixelArea | VECTOR4 | + * | wrapModeU | INTEGER OR STRING | + * | wrapModeV | INTEGER OR STRING | + * + * where pixelArea is a rectangular area. + * In its Vector4 value, the first two elements indicate the top-left position of the area, + * and the last two elements are the area width and height respectively. + * If not specified, the default value is [0.0, 0.0, 1.0, 1.0], i.e. the entire area of the image. + * + * where wrapModeU and wrapModeV separately decide how the texture should be sampled when the u and v coordinate exceeds the range of 0.0 to 1.0. + * Its value should be one of the following wrap mode: + * "DEFAULT" + * "CLAMP_TO_EDGE" + * "REPEAT" + * "MIRRORED_REPEAT" + */ + +class AnimatedImageVisual : public Visual::Base, public ConnectionTracker +{ + +public: + + /** + * @brief Create the animated image Visual using the image URL. + * + * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object + * @param[in] imageUrl The URL to svg resource to use + * @param[in] properties A Property::Map containing settings for this visual + * @return A smart-pointer to the newly allocated visual. + */ + static AnimatedImageVisualPtr New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl, const Property::Map& properties ); + + /** + * @brief Create the animated image visual using the image URL. + * + * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object + * @param[in] imageUrl The URL to animated image resource to use + */ + static AnimatedImageVisualPtr New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl ); + +public: // from Visual + + /** + * @copydoc Visual::Base::GetNaturalSize + */ + virtual void GetNaturalSize( Vector2& naturalSize ); + + /** + * @copydoc Visual::Base::CreatePropertyMap + */ + virtual void DoCreatePropertyMap( Property::Map& map ) const; + + /** + * @copydoc Visual::Base::CreateInstancePropertyMap + */ + virtual void DoCreateInstancePropertyMap( Property::Map& map ) const; + +protected: + + /** + * @brief Constructor. + * + * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object + */ + AnimatedImageVisual( VisualFactoryCache& factoryCache ); + + /** + * @brief A reference counted object may only be deleted by calling Unreference(). + */ + virtual ~AnimatedImageVisual(); + + /** + * @copydoc Visual::Base::DoSetProperties + */ + virtual void DoSetProperties( const Property::Map& propertyMap ); + + /** + * @copydoc Visual::Base::DoSetOnStage + */ + virtual void DoSetOnStage( Actor& actor ); + + /** + * @copydoc Visual::Base::DoSetOffStage + */ + virtual void DoSetOffStage( Actor& actor ); + + /** + * @copydoc Visual::Base::OnSetTransform + */ + virtual void OnSetTransform(); + +private: + + /** + * Load the animated image and pack the frames into atlas. + * @return That atlas texture. + */ + Texture PrepareAnimatedImage(); + + /** + * Display the next frame. It is called when the mFrameDelayTimes ticks. + */ + bool DisplayNextFrame(); + + // Undefined + AnimatedImageVisual( const AnimatedImageVisual& animatedImageVisual ); + + // Undefined + AnimatedImageVisual& operator=( const AnimatedImageVisual& animatedImageVisual ); + +private: + + Timer mFrameDelayTimer; + Dali::Vector mTextureRectContainer; + Dali::Vector mFrameDelayContainer; + Vector4 mPixelArea; + VisualUrl mImageUrl; + + ImageDimensions mImageSize; + uint32_t mCurrentFrameIndex; + Dali::WrapMode::Type mWrapModeU:3; + Dali::WrapMode::Type mWrapModeV:3; +}; + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali +#endif /* DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H */ diff --git a/dali-toolkit/internal/visuals/image/image-visual.cpp b/dali-toolkit/internal/visuals/image/image-visual.cpp index f3d4feb..2cf7cd7 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.cpp +++ b/dali-toolkit/internal/visuals/image/image-visual.cpp @@ -18,18 +18,19 @@ // CLASS HEADER #include "image-visual.h" -// EXTERNAL HEADER -#include // for strncasecmp +// EXTERNAL HEADERS +#include // for strlen() #include #include #include #include #include +#include #include #include #include -// INTERNAL HEADER +// INTERNAL HEADERS #include #include #include @@ -37,6 +38,7 @@ #include #include #include +#include namespace Dali { @@ -49,8 +51,6 @@ namespace Internal namespace { -const char HTTP_URL[] = "http://"; -const char HTTPS_URL[] = "https://"; // property names const char * const IMAGE_FITTING_MODE( "fittingMode" ); @@ -184,7 +184,38 @@ Geometry CreateGeometry( VisualFactoryCache& factoryCache, ImageDimensions gridS } //unnamed namespace -ImageVisual::ImageVisual( VisualFactoryCache& factoryCache ) + +ImageVisualPtr ImageVisual::New( VisualFactoryCache& factoryCache, + const VisualUrl& imageUrl, + const Property::Map& properties, + ImageDimensions size, + FittingMode::Type fittingMode, + Dali::SamplingMode::Type samplingMode ) +{ + ImageVisualPtr imageVisualPtr( new ImageVisual( factoryCache, imageUrl, size, fittingMode, samplingMode ) ); + imageVisualPtr->SetProperties( properties ); + return imageVisualPtr; +} + +ImageVisualPtr ImageVisual::New( VisualFactoryCache& factoryCache, + const VisualUrl& imageUrl, + ImageDimensions size, + FittingMode::Type fittingMode, + Dali::SamplingMode::Type samplingMode ) +{ + return new ImageVisual( factoryCache, imageUrl, size, fittingMode, samplingMode ); +} + +ImageVisualPtr ImageVisual::New( VisualFactoryCache& factoryCache, const Image& image ) +{ + return new ImageVisual( factoryCache, image ); +} + +ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, + const VisualUrl& imageUrl, + ImageDimensions size, + FittingMode::Type fittingMode, + Dali::SamplingMode::Type samplingMode ) : Visual::Base( factoryCache ), mPixelArea( FULL_TEXTURE_RECT ), mDesiredSize(), @@ -220,8 +251,22 @@ void ImageVisual::DoInitialize( Actor& actor, const Property::Map& propertyMap ) Scripting::GetEnumerationProperty( *fittingValue, FITTING_MODE_TABLE, FITTING_MODE_TABLE_COUNT, mFittingMode ); } - Property::Value* samplingValue = propertyMap.Find( Toolkit::ImageVisual::Property::SAMPLING_MODE, IMAGE_SAMPLING_MODE ); - if( samplingValue ) + + if( mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING && mImageUrl.IsValid() ) + { + // if sync loading is required, the loading should start + // immediately when new image url is set or the actor is off stage + // ( for on-stage actor with image url unchanged, resource loading + // is already finished ) + LoadResourceSynchronously(); + } +} + +void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& value ) +{ + switch( index ) + { + case Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING: { Scripting::GetEnumerationProperty( *samplingValue, SAMPLING_MODE_TABLE, SAMPLING_MODE_TABLE_COUNT, mSamplingMode ); } @@ -317,9 +362,9 @@ void ImageVisual::GetNaturalSize( Vector2& naturalSize ) const naturalSize.y = mDesiredSize.GetHeight(); return; } - else if( !mImageUrl.empty() ) + else if( mImageUrl.IsValid() && mImageUrl.GetLocation() == VisualUrl::LOCAL ) { - ImageDimensions dimentions = ResourceImage::GetImageSize( mImageUrl ); + ImageDimensions dimentions = Dali::GetClosestImageSize( mImageUrl.GetUrl() ); naturalSize.x = dimentions.GetWidth(); naturalSize.y = dimentions.GetHeight(); return; @@ -410,36 +455,16 @@ bool ImageVisual::IsSynchronousResourceLoading() const void ImageVisual::DoSynchronousResourceLoading() { - if( !mImageUrl.empty() ) + if( mImageUrl.IsValid() ) { - BitmapLoader loader = BitmapLoader::New( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode ); + BitmapLoader loader = BitmapLoader::New( mImageUrl.GetUrl(), mDesiredSize, mFittingMode, mSamplingMode ); loader.Load(); mPixels = loader.GetPixelData(); } } -Image ImageVisual::LoadImage( const std::string& url, bool synchronousLoading ) -{ - if( synchronousLoading ) - { - if( !mPixels ) - { - // use broken image - return VisualFactoryCache::GetBrokenVisualImage(); - } - Atlas image = Atlas::New( mPixels.GetWidth(), mPixels.GetHeight(), mPixels.GetPixelFormat() ); - image.Upload( mPixels, 0, 0 ); - return image; - } - else - { - ResourceImage resourceImage = Dali::ResourceImage::New( url, mDesiredSize, mFittingMode, mSamplingMode ); - resourceImage.LoadingFinishedSignal().Connect( this, &ImageVisual::OnImageLoaded ); - return resourceImage; - } -} -TextureSet ImageVisual::CreateTextureSet( Vector4& textureRect, const std::string& url, bool synchronousLoading ) +TextureSet ImageVisual::CreateTextureSet( Vector4& textureRect, bool synchronousLoading, bool attemptAtlasing ) { TextureSet textureSet; textureRect = FULL_TEXTURE_RECT; @@ -467,12 +492,17 @@ TextureSet ImageVisual::CreateTextureSet( Vector4& textureRect, const std::strin } else { - textureSet = mFactoryCache.GetAtlasManager()->Add(textureRect, url, mDesiredSize, mFittingMode, true, this ); - mImpl->mFlags |= Impl::IS_ATLASING_APPLIED; - if( !textureSet ) // big image, no atlasing + + if( attemptAtlasing ) + { + textureSet = mFactoryCache.GetAtlasManager()->Add( textureRect, mImageUrl.GetUrl(), mDesiredSize, mFittingMode, true, this ); + mImpl->mFlags |= Impl::IS_ATLASING_APPLIED; + } + if( !textureSet ) // big image, no atlasing or atlasing failed + { mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED; - ResourceImage resourceImage = Dali::ResourceImage::New( url, mDesiredSize, mFittingMode, mSamplingMode ); + ResourceImage resourceImage = Dali::ResourceImage::New( mImageUrl.GetUrl(), mDesiredSize, mFittingMode, mSamplingMode ); resourceImage.LoadingFinishedSignal().Connect( this, &ImageVisual::OnImageLoaded ); textureSet = TextureSet::New(); TextureSetImage( textureSet, 0u, resourceImage ); @@ -489,30 +519,22 @@ TextureSet ImageVisual::CreateTextureSet( Vector4& textureRect, const std::strin return textureSet; } -void ImageVisual::InitializeRenderer( const std::string& imageUrl ) +void ImageVisual::InitializeRenderer() { - if( imageUrl.empty() ) - { - return; - } - mImageUrl = imageUrl; - mImpl->mRenderer.Reset(); mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED; - if( !mImpl->mCustomShader && - ( strncasecmp( imageUrl.c_str(), HTTP_URL, sizeof(HTTP_URL) -1 ) != 0 ) && // ignore remote images - ( strncasecmp( imageUrl.c_str(), HTTPS_URL, sizeof(HTTPS_URL) -1 ) != 0 ) ) + if( !mImpl->mCustomShader && mImageUrl.GetLocation() == VisualUrl::LOCAL ) { bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE; bool cacheable = defaultWrapMode && mPixelArea == FULL_TEXTURE_RECT; - mImpl->mFlags &= ~Impl::IS_FROM_CACHE; - if( cacheable ) // fetch the renderer from cache if exist - { - mImpl->mRenderer = mFactoryCache.GetRenderer( imageUrl ); - mImpl->mFlags |= Impl::IS_FROM_CACHE; - } + + Vector4 atlasRect; + // texture set has to be created first as we need to know if atlasing succeeded or not + // when selecting the shader + TextureSet textures = CreateTextureSet( atlasRect, IsSynchronousResourceLoading(), true ); + CreateRenderer( textures ); if( !mImpl->mRenderer ) // new renderer is needed { @@ -543,11 +565,12 @@ void ImageVisual::InitializeRenderer( const std::string& imageUrl ) } else { - // for custom shader or remote image, renderer is not cached and atlas is not applied - mImpl->mFlags &= ~Impl::IS_FROM_CACHE; - mImpl->mRenderer = CreateRenderer(); - Image image = LoadImage( imageUrl, IsSynchronousResourceLoading() ); - ApplyImageToSampler( image ); + + // for custom shader or remote image, atlas is not applied + Vector4 atlasRect; // ignored in this case + TextureSet textures = CreateTextureSet( atlasRect, IsSynchronousResourceLoading(), false ); + CreateRenderer( textures ); + } } @@ -590,11 +613,10 @@ void ImageVisual::UploadCompleted() void ImageVisual::DoSetOnStage( Actor& actor ) { - mPlacementActor = actor; - if( !mImageUrl.empty() ) + if( mImageUrl.IsValid() ) { - InitializeRenderer( mImageUrl ); + InitializeRenderer(); } else { @@ -611,10 +633,12 @@ void ImageVisual::DoSetOnStage( Actor& actor ) void ImageVisual::DoSetOffStage( Actor& actor ) { //If we own the image then make sure we release it when we go off stage - if( !mImageUrl.empty() ) + + actor.RemoveRenderer( mImpl->mRenderer); + if( mImageUrl.IsValid() ) { - actor.RemoveRenderer( mImpl->mRenderer ); - CleanCache(mImageUrl); + RemoveFromAtlas( mImageUrl.GetUrl() ); + mImage.Reset(); } else @@ -632,9 +656,9 @@ void ImageVisual::DoCreatePropertyMap( Property::Map& map ) const bool sync = IsSynchronousResourceLoading(); map.Insert( SYNCHRONOUS_LOADING, sync ); - if( !mImageUrl.empty() ) + if( mImageUrl.IsValid() ) { - map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl ); + map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl() ); map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth() ); map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight() ); } @@ -658,6 +682,31 @@ void ImageVisual::DoCreatePropertyMap( Property::Map& map ) const map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV ); } + +void ImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const +{ + map.Clear(); + map.Insert( Toolkit::DevelVisual::Property::TYPE, Toolkit::Visual::IMAGE ); + if( mImageUrl.IsValid() ) + { + map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth() ); + map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight() ); + } + else if( mImage ) + { + map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, static_cast(mImage.GetWidth()) ); + map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, static_cast(mImage.GetHeight()) ); + } +} + +void ImageVisual::OnSetTransform() +{ + if( mImpl->mRenderer ) + { + mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT ); + } +} + Shader ImageVisual::GetImageShader( VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping ) { Shader shader; diff --git a/dali-toolkit/internal/visuals/image/image-visual.h b/dali-toolkit/internal/visuals/image/image-visual.h index d6947e3..49c427a 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.h +++ b/dali-toolkit/internal/visuals/image/image-visual.h @@ -28,6 +28,14 @@ #include #include +<<<<<<< HEAD +======= +// INTERNAL INCLUDES +#include +#include +#include + +>>>>>>> 8cfc796... Encapsulated visual URL in new VisualUrl class. namespace Dali { @@ -79,11 +87,45 @@ class ImageVisual: public Visual::Base, public ConnectionTracker, public AtlasUp public: /** +<<<<<<< HEAD * @brief Constructor. +======= + * @brief Create a new image visual with a URL. + * + * The visual will load the Image asynchronously when the associated actor is put on stage, and destroy the image when it is off stage + * + * @param[in] factoryCache The VisualFactoryCache object + * @param[in] imageUrl The URL of the image resource to use + * @param[in] properties A Property::Map containing settings for this visual + * @param[in] size The width and height to fit the loaded image to. + * @param[in] fittingMode The FittingMode of the resource to load + * @param[in] samplingMode The SamplingMode of the resource to load + * @return A smart-pointer to the newly allocated visual. + */ + static ImageVisualPtr New( VisualFactoryCache& factoryCache, + const VisualUrl& imageUrl, + const Property::Map& properties, + ImageDimensions size = ImageDimensions(), + FittingMode::Type fittingMode = FittingMode::DEFAULT, + Dali::SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR ); + + /** + * @brief Create a new image visual with a URL. + * + * The visual will load the Image asynchronously when the associated actor is put on stage, and destroy the image when it is off stage +>>>>>>> 8cfc796... Encapsulated visual URL in new VisualUrl class. * * @param[in] factoryCache The VisualFactoryCache object */ +<<<<<<< HEAD ImageVisual( VisualFactoryCache& factoryCache ); +======= + static ImageVisualPtr New( VisualFactoryCache& factoryCache, + const VisualUrl& imageUrl, + ImageDimensions size = ImageDimensions(), + FittingMode::Type fittingMode = FittingMode::DEFAULT, + Dali::SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR ); +>>>>>>> 8cfc796... Encapsulated visual URL in new VisualUrl class. /** * @brief A reference counted object may only be deleted by calling Unreference(). @@ -103,6 +145,27 @@ public: // from Visual virtual void DoCreatePropertyMap( Property::Map& map ) const; protected: +<<<<<<< HEAD +======= + + /** + * @brief Constructor with a URL. + * + * The visual will load the Image asynchronously when the associated actor is put on stage, and destroy the image when it is off stage + * + * @param[in] factoryCache The VisualFactoryCache object + * @param[in] imageUrl The URL of the image resource to use + * @param[in] size The width and height to fit the loaded image to. + * @param[in] fittingMode The FittingMode of the resource to load + * @param[in] samplingMode The SamplingMode of the resource to load + */ + ImageVisual( VisualFactoryCache& factoryCache, + const VisualUrl& imageUrl, + ImageDimensions size, + FittingMode::Type fittingMode, + Dali::SamplingMode::Type samplingMode ); + +>>>>>>> 8cfc796... Encapsulated visual URL in new VisualUrl class. /** * @copydoc Visual::Base::DoInitialize */ @@ -170,11 +233,9 @@ private: void ApplyImageToSampler( const Image& image ); /** - * @brief Initializes the Dali::Renderer from an image url string - * - * @param[in] imageUrl The image url string to intialize this ImageVisual from + * @brief Initializes the Dali::Renderer from the image url */ - void InitializeRenderer( const std::string& imageUrl ); + void InitializeRenderer(); /** * @brief Initializes the Dali::Renderer from an image handle @@ -221,7 +282,11 @@ private: * @param[in] url The URL of the image resource to use. * @param[in] synchronousLoading If true, the resource is loaded synchronously, otherwise asynchronously. */ +<<<<<<< HEAD TextureSet CreateTextureSet( Vector4& textureRect, const std::string& url, bool synchronousLoading ); +======= + TextureSet CreateTextureSet( Vector4& textureRect, bool synchronousLoading, bool attemptAtlasing ); +>>>>>>> 8cfc796... Encapsulated visual URL in new VisualUrl class. /** * Callback function of image resource loading succeed @@ -250,6 +315,10 @@ private: PixelData mPixels; Vector4 mPixelArea; WeakHandle mPlacementActor; +<<<<<<< HEAD +======= + VisualUrl mImageUrl; +>>>>>>> 8cfc796... Encapsulated visual URL in new VisualUrl class. std::string mImageUrl; Dali::ImageDimensions mDesiredSize; diff --git a/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp b/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp index 8a8b632..aad8409 100644 --- a/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp +++ b/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp @@ -200,20 +200,42 @@ void RegisterStretchProperties( Renderer& renderer, const char * uniformName, co /////////////////NPatchVisual//////////////// -NPatchVisual::NPatchVisual( VisualFactoryCache& factoryCache ) -: Visual::Base( factoryCache ), - mBorderOnly( false ) +NPatchVisualPtr NPatchVisual::New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl, const Property::Map& properties ) +{ + NPatchVisualPtr nPatchVisual( new NPatchVisual( factoryCache ) ); + nPatchVisual->mImageUrl = imageUrl; + nPatchVisual->SetProperties( properties ); + + return nPatchVisual; +} + +NPatchVisualPtr NPatchVisual::New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl ) + { } NPatchVisual::~NPatchVisual() { + + NPatchVisualPtr nPatchVisual( new NPatchVisual( factoryCache ) ); + VisualUrl visualUrl( image.GetUrl() ); + nPatchVisual->mImageUrl = visualUrl; + return nPatchVisual; } void NPatchVisual::DoInitialize( Actor& actor, const Property::Map& propertyMap ) { - Property::Value* imageURLValue = propertyMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME ); - if( imageURLValue ) + + naturalSize.x = 0u; + naturalSize.y = 0u; + + // load now if not already loaded + if( NPatchLoader::UNINITIALIZED_ID == mId && mImageUrl.IsLocal() ) + { + mId = mLoader.Load( mImageUrl.GetUrl(), mBorder ); + } + const NPatchLoader::Data* data; + if( mLoader.GetNPatchData( mId, data ) ) { //Read the borderOnly property first since InitialiseFromImage relies on mBorderOnly to be properly set Property::Value* borderOnlyValue = propertyMap.Find( Toolkit::ImageVisual::Property::BORDER_ONLY, BORDER_ONLY ); @@ -237,10 +259,12 @@ void NPatchVisual::DoInitialize( Actor& actor, const Property::Map& propertyMap void NPatchVisual::GetNaturalSize( Vector2& naturalSize ) const { - if( mImage ) + + // load when first go on stage + if( NPatchLoader::UNINITIALIZED_ID == mId && mImageUrl.IsLocal() ) { - naturalSize.x = mImage.GetWidth(); - naturalSize.y = mImage.GetHeight(); + mId = mLoader.Load( mImageUrl.GetUrl(), mBorder ); + } else if( !mImageUrl.empty() ) { @@ -254,7 +278,18 @@ void NPatchVisual::GetNaturalSize( Vector2& naturalSize ) const } } -void NPatchVisual::SetClipRect( const Rect& clipRect ) + +void NPatchVisual::DoCreatePropertyMap( Property::Map& map ) const +{ + map.Clear(); + map.Insert( Toolkit::DevelVisual::Property::TYPE, Toolkit::DevelVisual::N_PATCH ); + map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl() ); + map.Insert( Toolkit::ImageVisual::Property::BORDER_ONLY, mBorderOnly ); + map.Insert( Toolkit::DevelImageVisual::Property::BORDER, mBorder ); +} + +void NPatchVisual::DoCreateInstancePropertyMap( Property::Map& map ) const + { Visual::Base::SetClipRect( clipRect ); //ToDo: renderer responds to the clipRect change @@ -511,9 +546,16 @@ void NPatchVisual::InitializeFromImage( NinePatchImage nPatch ) mCroppedImage = nPatch.CreateCroppedBufferImage(); if( !mCroppedImage ) { - DALI_LOG_ERROR("'%s' specify a valid 9 patch image\n", mImageUrl.c_str() ); - InitializeFromBrokenImage(); - return; + + DALI_LOG_ERROR("The N patch image '%s' is not a valid N patch image\n", mImageUrl.GetUrl().c_str() ); + TextureSet textureSet = TextureSet::New(); + mImpl->mRenderer.SetTextures( textureSet ); + Image croppedImage = VisualFactoryCache::GetBrokenVisualImage(); + TextureSetImage( textureSet, 0u, croppedImage ); + mImpl->mRenderer.RegisterProperty( "uFixed[0]", Vector2::ZERO ); + mImpl->mRenderer.RegisterProperty( "uFixed[1]", Vector2::ZERO ); + mImpl->mRenderer.RegisterProperty( "uFixed[2]", Vector2::ZERO ); + mImpl->mRenderer.RegisterProperty( "uStretchTotal", Vector2( croppedImage.GetWidth(), croppedImage.GetHeight() ) ); } mImageSize = ImageDimensions( mCroppedImage.GetWidth(), mCroppedImage.GetHeight() ); diff --git a/dali-toolkit/internal/visuals/npatch/npatch-visual.h b/dali-toolkit/internal/visuals/npatch/npatch-visual.h index c4dcbc3..89b3a70 100644 --- a/dali-toolkit/internal/visuals/npatch/npatch-visual.h +++ b/dali-toolkit/internal/visuals/npatch/npatch-visual.h @@ -29,6 +29,11 @@ #include #include + +// INTERNAL INCLUDES +#include +#include + namespace Dali { @@ -54,11 +59,28 @@ class NPatchVisual: public Visual::Base public: /** - * @brief Constructor. + + * @brief Create an N-patch visual using an image URL. + * + * The visual will load the image synchronously when the associated actor is put on stage, and destroy the image when it is off stage + * + * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object + * @param[in] imageUrl The URL to 9 patch image resource to use + * @param[in] properties A Property::Map containing settings for this visual + * @return A smart-pointer to the newly allocated visual. + */ + static NPatchVisualPtr New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl, const Property::Map& properties ); + + /** + * @brief Create an N-patch visual using an image URL. + * + * The visual will load the image synchronously when the associated actor is put on stage, and destroy the image when it is off stage + * * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object */ - NPatchVisual( VisualFactoryCache& factoryCache ); + + static NPatchVisualPtr New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl ); /** * @brief A reference counted object may only be deleted by calling Unreference(). @@ -204,14 +226,13 @@ private: private: - NinePatchImage mImage; ///< The image to render if the visual was set from an NinePatchImage, empty otherwise - Image mCroppedImage; - std::string mImageUrl; ///< The url to the image resource to render if the visual was set from an image resource url, empty otherwise - NinePatchImage::StretchRanges mStretchPixelsX; - NinePatchImage::StretchRanges mStretchPixelsY; - ImageDimensions mImageSize; - bool mBorderOnly; + NPatchLoader& mLoader; ///< reference to N patch loader for fast access + VisualUrl mImageUrl; ///< The url to the N patch to load + std::size_t mId; ///< id of the N patch (from loader/cache) + bool mBorderOnly; ///< if only border is desired + Rect< int > mBorder; ///< The size of the border + }; } // namespace Internal diff --git a/dali-toolkit/internal/visuals/svg/svg-visual.cpp b/dali-toolkit/internal/visuals/svg/svg-visual.cpp index f1658f1..e5f3fa8 100644 --- a/dali-toolkit/internal/visuals/svg/svg-visual.cpp +++ b/dali-toolkit/internal/visuals/svg/svg-visual.cpp @@ -53,10 +53,32 @@ namespace Toolkit namespace Internal { + +SvgVisualPtr SvgVisual::New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl, const Property::Map& properties ) +{ + SvgVisualPtr svgVisual( new SvgVisual( factoryCache ) ); + svgVisual->ParseFromUrl( imageUrl ); + svgVisual->SetProperties( properties ); + + return svgVisual; +} + +SvgVisualPtr SvgVisual::New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl ) +{ + SvgVisualPtr svgVisual( new SvgVisual( factoryCache ) ); + svgVisual->ParseFromUrl( imageUrl ); + + return svgVisual; +} + SvgVisual::SvgVisual( VisualFactoryCache& factoryCache ) : Visual::Base( factoryCache ), mAtlasRect( FULL_TEXTURE_RECT ), - mParsedImage( NULL ) + mImageUrl( ), + mParsedImage( NULL ), + mPlacementActor(), + mVisualSize(Vector2::ZERO) + { // the rasterized image is with pre-multiplied alpha format mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA; @@ -148,10 +170,12 @@ void SvgVisual::SetSize( const Vector2& size ) void SvgVisual::DoCreatePropertyMap( Property::Map& map ) const { map.Clear(); - map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE ); - if( !mImageUrl.empty() ) + + map.Insert( Toolkit::DevelVisual::Property::TYPE, Toolkit::DevelVisual::SVG ); + if( mImageUrl.IsValid() ) + { - map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl ); + map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl() ); } } @@ -161,24 +185,16 @@ void SvgVisual::SetImage( const std::string& imageUrl, ImageDimensions size ) { mImageUrl = imageUrl; - NSVGimage* parsedImageOld = mParsedImage; +void SvgVisual::ParseFromUrl( const VisualUrl& imageUrl ) +{ + mImageUrl = imageUrl; + if( mImageUrl.IsLocal() ) + { Vector2 dpi = Stage::GetCurrent().GetDpi(); float meanDpi = (dpi.height + dpi.width) * 0.5f; - mParsedImage = nsvgParseFromFile(mImageUrl.c_str(), UNITS, meanDpi); - - if( size.GetWidth() != 0u && size.GetHeight() != 0u) - { - mImpl->mSize.x = size.GetWidth(); - mImpl->mSize.y = size.GetHeight(); - } - - if( mImpl->mSize != Vector2::ZERO && GetIsOnStage() ) - { - AddRasterizationTask( mImpl->mSize ); - } + mParsedImage = nsvgParseFromFile( mImageUrl.GetUrl().c_str(), UNITS, meanDpi ); - mFactoryCache.GetSVGRasterizationThread()->DeleteImage( parsedImageOld ); } } diff --git a/dali-toolkit/internal/visuals/svg/svg-visual.h b/dali-toolkit/internal/visuals/svg/svg-visual.h index 4fc6030..fba21f3 100644 --- a/dali-toolkit/internal/visuals/svg/svg-visual.h +++ b/dali-toolkit/internal/visuals/svg/svg-visual.h @@ -23,6 +23,7 @@ // INTERNAL INCLUDES #include +#include struct NSVGimage; @@ -54,12 +55,14 @@ public: * * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object */ - SvgVisual( VisualFactoryCache& factoryCache ); + + static SvgVisualPtr New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl, const Property::Map& properties ); /** * @brief A reference counted object may only be deleted by calling Unreference(). */ - ~SvgVisual(); + + static SvgVisualPtr New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl ); public: // from Visual @@ -122,6 +125,15 @@ public: void ApplyRasterizedImage( PixelData rasterizedPixelData ); private: + + /** + * @brief Parses the SVG Image from the set URL. + * + * @param[in] imageUrl The URL of the image to parse the SVG from. + */ + void ParseFromUrl( const VisualUrl& imageUrl ); + + /** * @bried Rasterize the svg with the given size, and add it to the visual. * @@ -138,7 +150,7 @@ private: private: Vector4 mAtlasRect; - std::string mImageUrl; + VisualUrl mImageUrl; NSVGimage* mParsedImage; WeakHandle mPlacementActor; diff --git a/dali-toolkit/internal/visuals/visual-factory-impl.cpp b/dali-toolkit/internal/visuals/visual-factory-impl.cpp index c1bd457..ef0d7e5 100644 --- a/dali-toolkit/internal/visuals/visual-factory-impl.cpp +++ b/dali-toolkit/internal/visuals/visual-factory-impl.cpp @@ -39,6 +39,8 @@ #include #include #include + +#include #include #include @@ -136,20 +138,33 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& property std::string imageUrl; if( imageURLValue && imageURLValue->Get( imageUrl ) ) { - if( NinePatchImage::IsNinePatchUrl( imageUrl ) ) - { - visualPtr = new NPatchVisual( *( mFactoryCache.Get() ) ); - } - else if( SvgVisual::IsSvgUrl( imageUrl ) ) - { - visualPtr = new SvgVisual( *( mFactoryCache.Get() ) ); - } - else + + VisualUrl visualUrl( imageUrl ); + + switch( visualUrl.GetType() ) { - visualPtr = new ImageVisual( *( mFactoryCache.Get() ) ); + case VisualUrl::N_PATCH: + { + visualPtr = NPatchVisual::New( *( mFactoryCache.Get() ), visualUrl, propertyMap ); + break; + } + case VisualUrl::SVG: + { + visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), visualUrl, propertyMap ); + break; + } + case VisualUrl::GIF: + { + visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), visualUrl, propertyMap ); + break; + } + case VisualUrl::REGULAR_IMAGE: + { + visualPtr = ImageVisual::New( *( mFactoryCache.Get() ), visualUrl, propertyMap ); + break; + } } } - break; } @@ -222,29 +237,33 @@ Toolkit::Visual::Base VisualFactory::CreateVisual( const std::string& url, Image mFactoryCache = new VisualFactoryCache(); } - if( mDebugEnabled ) - { - return Toolkit::Visual::Base( new WireframeVisual( *( mFactoryCache.Get() ) ) ); - } - - if( NinePatchImage::IsNinePatchUrl( url ) ) - { - NPatchVisual* visualPtr = new NPatchVisual( *( mFactoryCache.Get() ) ); - visualPtr->SetImage( url ); + Visual::BasePtr visualPtr; - return Toolkit::Visual::Base( visualPtr ); - } - else if( SvgVisual::IsSvgUrl( url ) ) + // first resolve url type to know which visual to create + VisualUrl visualUrl( url ); + switch( visualUrl.GetType() ) { - SvgVisual* visualPtr = new SvgVisual( *( mFactoryCache.Get() ) ); - visualPtr->SetImage( url, size ); - return Toolkit::Visual::Base( visualPtr ); + case VisualUrl::N_PATCH: + { + visualPtr = NPatchVisual::New( *( mFactoryCache.Get() ), visualUrl ); + break; + } + case VisualUrl::SVG: + { + visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), visualUrl ); + break; + } + case VisualUrl::GIF: + { + visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), visualUrl ); + break; + } + case VisualUrl::REGULAR_IMAGE: + { + visualPtr = ImageVisual::New( *( mFactoryCache.Get() ), visualUrl, size ); + break; + } } - else - { - ImageVisual* visualPtr = new ImageVisual( *( mFactoryCache.Get() )); - Actor actor; - visualPtr->SetImage( actor, url, size ); return Toolkit::Visual::Base( visualPtr ); } diff --git a/dali-toolkit/internal/visuals/visual-url.cpp b/dali-toolkit/internal/visuals/visual-url.cpp new file mode 100644 index 0000000..c3c675d --- /dev/null +++ b/dali-toolkit/internal/visuals/visual-url.cpp @@ -0,0 +1,232 @@ +/* + * 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 + +// EXTERNAL HEADERS +#include // for toupper() + +namespace Dali +{ +namespace Toolkit +{ +namespace Internal +{ + +namespace +{ + +VisualUrl::Location 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 ) + { + if( urlCStr[3] == ':' || urlCStr[4] == ':' || urlCStr[5] == ':' ) + { + int flags = 0x0F; + for( unsigned int i=0; i < sizeof(HTTPS); ++i ) + { + 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] ) + { + flags &= ~MATCH_HTTPS; + } + + if( (flags & (MATCH_FTP | MATCH_SSH | MATCH_HTTP | MATCH_HTTPS )) == 0 ) + { + break; + } + } + + if( flags ) + { + return VisualUrl::REMOTE; + } + } + } + return VisualUrl::LOCAL; +} + + +VisualUrl::Type ResolveType( const std::string& url ) +{ + // if only one char in string, can only be regular image + const std::size_t count = url.size(); + if( count > 0 ) + { + // parsing from the end for better chance of early outs + enum { SUFFIX, HASH, HASH_DOT } state = SUFFIX; + char SVG[ 4 ] = { 'g', 'v', 's', '.' }; + char GIF[ 4 ] = { 'f', 'i', 'g', '.' }; + unsigned int svgScore = 0; + unsigned int gifScore = 0; + int index = count; + while( --index >= 0 ) + { + const char currentChar = url[ index ]; + const std::size_t offsetFromEnd = count - index - 1u; + if( ( offsetFromEnd < sizeof(SVG) )&&( tolower( currentChar ) == SVG[ offsetFromEnd ] ) ) + { + // early out if SVG as can't be used in N patch for now + if( ++svgScore == sizeof(SVG) ) + { + return VisualUrl::SVG; + } + } + if( ( offsetFromEnd < sizeof(GIF) )&&( tolower( currentChar ) == GIF[ offsetFromEnd ] ) ) + { + // early out if GIF + if( ++gifScore == sizeof(GIF) ) + { + return VisualUrl::GIF; + } + } + switch( state ) + { + case SUFFIX: + { + if( '.' == currentChar ) + { + state = HASH; + } + break; + } + case HASH: + { + if( ( '#' == currentChar ) || ( '9' == currentChar ) ) + { + state = HASH_DOT; + } + else + { + // early out, not a valid N/9-patch URL + return VisualUrl::REGULAR_IMAGE; + } + break; + } + case HASH_DOT: + { + if( '.' == currentChar ) + { + return VisualUrl::N_PATCH; + } + else + { + // early out, not a valid N/9-patch URL + return VisualUrl::REGULAR_IMAGE; + } + break; + } + } + } + } + // if we got here it is a regular image + return VisualUrl::REGULAR_IMAGE; +} + +} + + +VisualUrl::VisualUrl() +: mUrl(), + mType( VisualUrl::REGULAR_IMAGE ), + mLocation( VisualUrl::LOCAL ) +{ +} + +VisualUrl::VisualUrl( const std::string& url ) +: mUrl( url ), + mType( VisualUrl::REGULAR_IMAGE ), + mLocation( VisualUrl::LOCAL ) +{ + if( ! url.empty() ) + { + mLocation = ResolveLocation( url ); + mType = ResolveType( url ); + } +} + +VisualUrl::VisualUrl( const VisualUrl& url ) +: mUrl( url.mUrl ), + mType( url.mType ), + mLocation( url.mLocation ) +{ +} + +VisualUrl& VisualUrl::operator=( const VisualUrl& url ) +{ + if( &url != this ) + { + mUrl = url.mUrl; + mType = url.mType; + mLocation = url.mLocation; + } + return *this; +} + +const std::string& VisualUrl::GetUrl() const +{ + return mUrl; +} + +VisualUrl::Type VisualUrl::GetType() const +{ + return mType; +} + +VisualUrl::Location VisualUrl::GetLocation() const +{ + return mLocation; +} + +bool VisualUrl::IsValid() const +{ + return mUrl.size() > 0u; +} + +bool VisualUrl::IsLocal() const +{ + return mLocation == VisualUrl::LOCAL; +} + + + +} // Internal +} // Toolkit +} // Dali diff --git a/dali-toolkit/internal/visuals/visual-url.h b/dali-toolkit/internal/visuals/visual-url.h new file mode 100644 index 0000000..d9ed48a --- /dev/null +++ b/dali-toolkit/internal/visuals/visual-url.h @@ -0,0 +1,119 @@ +#ifndef DALI_TOOLKIT_INTERNAL_VISUAL_URL_H +#define DALI_TOOLKIT_INTERNAL_VISUAL_URL_H + +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +class VisualUrl +{ +public: + + /** + * The type of the URL based on the string contents + */ + enum Type + { + REGULAR_IMAGE, + N_PATCH, + SVG, + GIF + }; + + enum Location + { + LOCAL, + REMOTE + }; + + /** + * Default Constructor. + * Resulting URL is not valid + */ + VisualUrl(); + + /** + * Constructor. + * Determines type of visual and whether the url is local or remote + * @param[in] url The URL to store and resolve + */ + VisualUrl( const std::string& url ); + + /** + * Copy constructor + * @param[in] url The VisualUrl to copy + */ + VisualUrl( const VisualUrl& url ); + + /** + * Assignment operator + * @param[in] url The VisualUrl to copy + */ + VisualUrl& operator=( const VisualUrl& url ); + + /** + * Get the full URL + * @return The url + */ + const std::string& GetUrl() const; + + /** + * Get the visual type of the URL + * @return The visual type of the URL + */ + Type GetType() const; + + /** + * Is the URL is local to the device, or remote? + * @return the location of the resource + */ + Location GetLocation() const; + + /** + * Is the URL valid? + * @return true if the URL has length + */ + bool IsValid() const; + + /** + * @return true if the location is LOCAL + */ + bool IsLocal() const; + +private: + std::string mUrl; + Type mType; + Location mLocation; +}; + + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali + +#endif /* DALI_TOOLKIT_INTERNAL_VISUAL_URL_H */ -- 2.7.4