From a4b26c19783f73d4e0f3a9fdd23f5a1810406734 Mon Sep 17 00:00:00 2001 From: "Eunki, Hong" Date: Tue, 8 Jun 2021 15:07:20 +0900 Subject: [PATCH] Generate url and load texture from encoded image buffer Make some way to load image from raw-buffer stream. This raw-buffer will alive when some actor contain this buffer. Limitation : animated-image, vector-image, animated-vector-image not working now. Will support another patch 1. Generate url from encoded raw buffer like this ImageUrl url = Toolkit::Image::GenerateUrl(const EncodedImageBuffer &); 2. When we use URL as this string, we can load it like normal LOCAL file. ImageView imageView = Toolkit::ImageView::New(url.GetUrl()); 3. Buffer will automatically removed when ImageUrl scope is out-of-date, and no actor use it. NOTE : even ImageUrl lifecycle is done, cached texture can use internally. Change-Id: I517d9526d13a6b761792dcb7054864643f209b67 Signed-off-by: Eunki, Hong --- .../src/dali-toolkit-internal/CMakeLists.txt | 1 + .../utc-Dali-TextureManager.cpp | 312 +++++++++++++++++++++ .../dali-toolkit-internal/utc-Dali-VisualUrl.cpp | 48 ++++ automated-tests/src/dali-toolkit/CMakeLists.txt | 1 + .../test-encoded-image-buffer.cpp | 43 +++ .../test-encoded-image-buffer.h | 32 +++ .../src/dali-toolkit/utc-Dali-Image.cpp | 15 + .../src/dali-toolkit/utc-Dali-ImageView.cpp | 149 +++++++++- .../src/dali-toolkit/utc-Dali-ImageVisual.cpp | 103 +++++++ dali-toolkit/devel-api/image-loader/image-atlas.h | 4 +- .../image-loader/async-image-loader-impl.cpp | 22 +- .../internal/image-loader/image-load-thread.cpp | 31 +- .../internal/image-loader/image-load-thread.h | 20 ++ .../internal/image-loader/image-url-impl.cpp | 42 ++- .../internal/image-loader/image-url-impl.h | 11 + .../internal/visuals/image/image-visual.cpp | 2 +- .../internal/visuals/npatch/npatch-visual.cpp | 4 +- .../internal/visuals/texture-manager-impl.cpp | 152 +++++++++- .../internal/visuals/texture-manager-impl.h | 66 ++++- dali-toolkit/internal/visuals/visual-url.cpp | 90 ++++-- dali-toolkit/internal/visuals/visual-url.h | 16 +- dali-toolkit/public-api/image-loader/image-url.cpp | 6 + dali-toolkit/public-api/image-loader/image-url.h | 10 + dali-toolkit/public-api/image-loader/image.cpp | 5 + dali-toolkit/public-api/image-loader/image.h | 10 + 25 files changed, 1138 insertions(+), 57 deletions(-) create mode 100644 automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-encoded-image-buffer.cpp create mode 100644 automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-encoded-image-buffer.h diff --git a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt index d50921c..c1b0ae6 100755 --- a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt @@ -80,6 +80,7 @@ SET(TEST_HARNESS_SOURCES ../dali-toolkit/dali-toolkit-test-utils/test-animation-data.cpp ../dali-toolkit/dali-toolkit-test-utils/test-application.cpp ../dali-toolkit/dali-toolkit-test-utils/test-button.cpp + ../dali-toolkit/dali-toolkit-test-utils/test-encoded-image-buffer.cpp ../dali-toolkit/dali-toolkit-test-utils/test-harness.cpp ../dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.cpp ../dali-toolkit/dali-toolkit-test-utils/test-graphics-sync-impl.cpp diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp index 9098be8..04c51af 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp @@ -26,6 +26,9 @@ #include #include #include +#include ///< For VisualFactory's member TextureManager. + +#include #if defined(ELDBUS_ENABLED) #include @@ -147,6 +150,315 @@ int UtcTextureManagerGenerateHash(void) END_TEST; } +int UtcTextureManagerEncodedImageBuffer(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcTextureManagerEncodedImageBuffer" ); + + auto visualFactory = Toolkit::VisualFactory::Get(); + auto& textureManager = GetImplementation(visualFactory).GetTextureManager(); // Use VisualFactory's texture manager + + // Get encoded raw-buffer image and generate url + EncodedImageBuffer buffer1 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME); + EncodedImageBuffer buffer2 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME); + + std::string url1 = textureManager.AddExternalEncodedImageBuffer(buffer1); + std::string url2 = textureManager.AddExternalEncodedImageBuffer(buffer1); + std::string url3 = VisualUrl::CreateBufferUrl(""); ///< Impossible Buffer URL. for coverage + + // Check if same EncodedImageBuffer get same url + DALI_TEST_CHECK(url1 == url2); + // Reduce reference count + textureManager.RemoveExternalEncodedImageBuffer(url1); + // Check whethere url1 still valid + DALI_TEST_CHECK(textureManager.GetEncodedImageBuffer(url1)); + + url2 = textureManager.AddExternalEncodedImageBuffer(buffer2); + // Check if difference EncodedImageBuffer get difference url + DALI_TEST_CHECK(url1 != url2); + + auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; + + TestObserver observer1; + textureManager.RequestLoad( + url1, + ImageDimensions(), + FittingMode::SCALE_TO_FILL, + SamplingMode::BOX_THEN_LINEAR, + TextureManager::NO_ATLAS, + &observer1, + true, ///< orientationCorrection + TextureManager::ReloadPolicy::CACHED, + preMultiply); + + DALI_TEST_EQUALS( observer1.mLoaded, false, TEST_LOCATION ); + DALI_TEST_EQUALS( observer1.mObserverCalled, false, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( observer1.mLoaded, true, TEST_LOCATION ); + DALI_TEST_EQUALS( observer1.mObserverCalled, true, TEST_LOCATION ); + DALI_TEST_EQUALS( observer1.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION ); + + TestObserver observer2; + // Syncload + Devel::PixelBuffer pixelBuffer = textureManager.LoadPixelBuffer( + url2, + ImageDimensions(), + FittingMode::SCALE_TO_FILL, + SamplingMode::BOX_THEN_LINEAR, + true, ///< synchronousLoading + &observer2, + true, ///< orientationCorrection + preMultiply); + + DALI_TEST_CHECK( pixelBuffer ); + DALI_TEST_EQUALS( observer2.mLoaded, false, TEST_LOCATION ); + DALI_TEST_EQUALS( observer2.mObserverCalled, false, TEST_LOCATION ); + + // Asyncload + pixelBuffer = textureManager.LoadPixelBuffer( + url2, + ImageDimensions(), + FittingMode::SCALE_TO_FILL, + SamplingMode::BOX_THEN_LINEAR, + false, ///< synchronousLoading + &observer2, + true, ///< orientationCorrection + preMultiply); + + DALI_TEST_EQUALS( observer2.mLoaded, false, TEST_LOCATION ); + DALI_TEST_EQUALS( observer2.mObserverCalled, false, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( observer2.mLoaded, true, TEST_LOCATION ); + DALI_TEST_EQUALS( observer2.mObserverCalled, true, TEST_LOCATION ); + DALI_TEST_EQUALS( observer2.mCompleteType, TestObserver::CompleteType::LOAD_COMPLETE, TEST_LOCATION ); + + textureManager.RemoveExternalEncodedImageBuffer(url1); + textureManager.RemoveExternalEncodedImageBuffer(url2); + + // Now url1 and url2 is invalid type. mLoaded will return false + + TestObserver observer3; + textureManager.RequestLoad( + url1, + ImageDimensions(), + FittingMode::SCALE_TO_FILL, + SamplingMode::BOX_THEN_LINEAR, + TextureManager::NO_ATLAS, + &observer3, + true, ///< orientationCorrection + TextureManager::ReloadPolicy::CACHED, + preMultiply); + + // Load will be success because url1 is cached + DALI_TEST_EQUALS( observer3.mLoaded, true, TEST_LOCATION ); + DALI_TEST_EQUALS( observer3.mObserverCalled, true, TEST_LOCATION ); + DALI_TEST_EQUALS( observer3.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION ); + + TestObserver observer4; + textureManager.RequestLoad( + url2, + ImageDimensions(), + FittingMode::SCALE_TO_FILL, + SamplingMode::BOX_THEN_LINEAR, + TextureManager::NO_ATLAS, + &observer4, + true, ///< orientationCorrection + TextureManager::ReloadPolicy::FORCED, + preMultiply); + + DALI_TEST_EQUALS( observer4.mLoaded, false, TEST_LOCATION ); + DALI_TEST_EQUALS( observer4.mObserverCalled, false, TEST_LOCATION ); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + // Load will be failed becuase reloadpolicy is forced + DALI_TEST_EQUALS( observer4.mLoaded, false, TEST_LOCATION ); + DALI_TEST_EQUALS( observer4.mObserverCalled, true, TEST_LOCATION ); + DALI_TEST_EQUALS( observer4.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION ); + + TestObserver observer5; + pixelBuffer = textureManager.LoadPixelBuffer( + url2, + ImageDimensions(), + FittingMode::SCALE_TO_FILL, + SamplingMode::BOX_THEN_LINEAR, + true, ///< synchronousLoading + &observer5, + true, ///< orientationCorrection + preMultiply); + + // Load will be faild because synchronousLoading doesn't use cached texture + DALI_TEST_CHECK( !pixelBuffer ); + DALI_TEST_EQUALS( observer5.mLoaded, false, TEST_LOCATION ); + DALI_TEST_EQUALS( observer5.mObserverCalled, false, TEST_LOCATION ); + + TestObserver observer6; + pixelBuffer = textureManager.LoadPixelBuffer( + url3, + ImageDimensions(), + FittingMode::SCALE_TO_FILL, + SamplingMode::BOX_THEN_LINEAR, + false, ///< synchronousLoading + &observer6, + true, ///< orientationCorrection + preMultiply); + + DALI_TEST_EQUALS( observer6.mLoaded, false, TEST_LOCATION ); + DALI_TEST_EQUALS( observer6.mObserverCalled, false, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + // Load will be failed because url3 is invalid URL + DALI_TEST_EQUALS( observer6.mLoaded, false, TEST_LOCATION ); + DALI_TEST_EQUALS( observer6.mObserverCalled, true, TEST_LOCATION ); + DALI_TEST_EQUALS( observer6.mCompleteType, TestObserver::CompleteType::LOAD_COMPLETE, TEST_LOCATION ); + + END_TEST; +} + +int UtcTextureManagerEncodedImageBufferReferenceCount(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcTextureManagerEncodedImageBuffer check reference count works well" ); + + auto visualFactory = Toolkit::VisualFactory::Get(); + auto& textureManager = GetImplementation(visualFactory).GetTextureManager(); // Use VisualFactory's texture manager + + // Get encoded raw-buffer image and generate url + EncodedImageBuffer buffer1 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME); + EncodedImageBuffer buffer2 = ConvertFileToEncodedImageBuffer(TEST_IMAGE_FILE_NAME); + + std::string url1 = textureManager.AddExternalEncodedImageBuffer(buffer1); + std::string url2 = textureManager.AddExternalEncodedImageBuffer(buffer1); + + // Check if same EncodedImageBuffer get same url + DALI_TEST_CHECK(url1 == url2); + + // Reduce reference count + textureManager.RemoveExternalEncodedImageBuffer(url1); + // Check whethere url1 still valid + DALI_TEST_CHECK(textureManager.GetEncodedImageBuffer(url1)); + + // Reduce reference count + textureManager.RemoveExternalEncodedImageBuffer(url1); + // Check whethere url1 is not valid anymore + DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url1)); + + // UseExternalTexture doesn't create new buffer. + // So, reference count is still zero. + textureManager.UseExternalResource(url1); + DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url1)); + + url1 = textureManager.AddExternalEncodedImageBuffer(buffer1); + // Check if difference EncodedImageBuffer get difference url + // Previous EncodedImageBuffer was deleted, so we get new url even same buffer. + DALI_TEST_CHECK(url1 != url2); + + url2 = textureManager.AddExternalEncodedImageBuffer(buffer2); + // Check if difference EncodedImageBuffer get difference url + DALI_TEST_CHECK(url1 != url2); + + auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; + + // url1 load image by cache + TestObserver observer1; + textureManager.RequestLoad( + url1, + ImageDimensions(), + FittingMode::SCALE_TO_FILL, + SamplingMode::BOX_THEN_LINEAR, + TextureManager::NO_ATLAS, + &observer1, + true, ///< orientationCorrection + TextureManager::ReloadPolicy::CACHED, + preMultiply); + + DALI_TEST_EQUALS( observer1.mLoaded, false, TEST_LOCATION ); + DALI_TEST_EQUALS( observer1.mObserverCalled, false, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( observer1.mLoaded, true, TEST_LOCATION ); + DALI_TEST_EQUALS( observer1.mObserverCalled, true, TEST_LOCATION ); + DALI_TEST_EQUALS( observer1.mCompleteType, TestObserver::CompleteType::UPLOAD_COMPLETE, TEST_LOCATION ); + + // LoadPixelBuffer doen't use cache. url2 will not be cached + TestObserver observer2; + Devel::PixelBuffer pixelBuffer = textureManager.LoadPixelBuffer( + url2, + ImageDimensions(), + FittingMode::SCALE_TO_FILL, + SamplingMode::BOX_THEN_LINEAR, + false, ///< synchronousLoading + &observer2, + true, ///< orientationCorrection + preMultiply); + + DALI_TEST_EQUALS( observer2.mLoaded, false, TEST_LOCATION ); + DALI_TEST_EQUALS( observer2.mObserverCalled, false, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( observer2.mLoaded, true, TEST_LOCATION ); + DALI_TEST_EQUALS( observer2.mObserverCalled, true, TEST_LOCATION ); + DALI_TEST_EQUALS( observer2.mCompleteType, TestObserver::CompleteType::LOAD_COMPLETE, TEST_LOCATION ); + + // Decrease each url's reference count. + textureManager.RemoveExternalEncodedImageBuffer(url1); + textureManager.RemoveExternalEncodedImageBuffer(url2); + + // url1 buffer is still have 1 reference count because it is cached. + // But url2 not valid because it is not cached. + DALI_TEST_CHECK(textureManager.GetEncodedImageBuffer(url1)); + DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url2)); + + // Check url1 buffer have 1 reference count because it is cached. + textureManager.RemoveExternalEncodedImageBuffer(url1); + DALI_TEST_CHECK(!textureManager.GetEncodedImageBuffer(url1)); + + END_TEST; +} + + int UtcTextureManagerCachingForDifferentLoadingType(void) { ToolkitTestApplication application; diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualUrl.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualUrl.cpp index c57ec89..767c1f8 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualUrl.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualUrl.cpp @@ -54,6 +54,18 @@ int UtcDaliVisualUrlConstructor(void) DALI_TEST_EQUALS( true, visualUrl4.IsValid(), TEST_LOCATION ); DALI_TEST_EQUALS( visualUrl4.GetType(), VisualUrl::REGULAR_IMAGE, TEST_LOCATION ); DALI_TEST_EQUALS( visualUrl4.GetProtocolType(), VisualUrl::TEXTURE, TEST_LOCATION ); + + VisualUrl visualUrl6("enbuf://0"); + visualUrl6 = visualUrl; + DALI_TEST_EQUALS( true, visualUrl6.IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( visualUrl6.GetType(), VisualUrl::GIF, TEST_LOCATION ); + DALI_TEST_EQUALS( visualUrl6.GetProtocolType(), VisualUrl::LOCAL, TEST_LOCATION ); + + VisualUrl visualUrl7("enbuf://1"); + visualUrl6 = visualUrl7; + DALI_TEST_EQUALS( true, visualUrl6.IsValid(), TEST_LOCATION ); + DALI_TEST_EQUALS( visualUrl6.GetType(), VisualUrl::REGULAR_IMAGE, TEST_LOCATION ); + DALI_TEST_EQUALS( visualUrl6.GetProtocolType(), VisualUrl::BUFFER, TEST_LOCATION ); END_TEST; } @@ -233,6 +245,15 @@ int UtcDaliVisualUrlLocationP(void) 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 ); + DALI_TEST_EQUALS( VisualUrl::BUFFER, VisualUrl("enbuf://").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::BUFFER, VisualUrl("enbuf://1234").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::BUFFER, VisualUrl("ENBUF://1234").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::BUFFER, VisualUrl("enbuf://.gif").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::BUFFER, VisualUrl("enbuf://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::BUFFER, VisualUrl("enbuf://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::BUFFER, VisualUrl("enbuf://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::BUFFER, VisualUrl("enbuf://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION ); + END_TEST; } @@ -262,6 +283,8 @@ int UtcDaliVisualUrlLocationN(void) 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("fsh://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("stp://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 ); @@ -280,6 +303,18 @@ int UtcDaliVisualUrlLocationN(void) DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("dali:5/1").GetProtocolType(), TEST_LOCATION ); DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("dali:/61").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("eunki://1").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("enbu://1").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("eubnf://1").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("1nbuf://1").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("e2bun://1").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("en3uf://1").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("enb4f://1").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("enbu5://1").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("enbuf6//1").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("enbuf:7/1").GetProtocolType(), TEST_LOCATION ); + DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("enbuf:/81").GetProtocolType(), TEST_LOCATION ); + END_TEST; } @@ -367,6 +402,7 @@ int UtcDaliVisualUrlGetLocationP(void) DALI_TEST_EQUAL( "a", VisualUrl("http://a").GetLocation() ); DALI_TEST_EQUAL( "1", VisualUrl("dali://1").GetLocation() ); + DALI_TEST_EQUAL( "4", VisualUrl("enbuf://4").GetLocation() ); DALI_TEST_EQUAL( "", VisualUrl("ftp://").GetLocation() ); DALI_TEST_EQUAL( "http://", VisualUrl("http://http://").GetLocation() ); @@ -381,6 +417,7 @@ int UtcDaliVisualUrlGetLocationN(void) 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( "enbuf:/2", VisualUrl("enbuf:/2").GetLocation() ); DALI_TEST_EQUAL( "", VisualUrl("http:/http://").GetLocation() ); END_TEST; @@ -396,3 +433,14 @@ int UtcDaliVisualUrlCreateTextureUrl(void) END_TEST; } + +int UtcDaliVisualUrlCreateBufferUrl(void) +{ + tet_infoline( "UtcDaliVisualUrl CreateBufferUrl" ); + + DALI_TEST_EQUAL( "enbuf://a", VisualUrl::CreateBufferUrl( "a" ) ); + DALI_TEST_EQUAL( "enbuf://1234", VisualUrl::CreateBufferUrl( "1234" ) ); + DALI_TEST_EQUAL( "enbuf://", VisualUrl::CreateBufferUrl( "" ) ); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit/CMakeLists.txt b/automated-tests/src/dali-toolkit/CMakeLists.txt index 0e984f0..b3c04d4 100755 --- a/automated-tests/src/dali-toolkit/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit/CMakeLists.txt @@ -112,6 +112,7 @@ SET(TEST_HARNESS_SOURCES dali-toolkit-test-utils/test-animation-data.cpp dali-toolkit-test-utils/test-application.cpp dali-toolkit-test-utils/test-button.cpp + dali-toolkit-test-utils/test-encoded-image-buffer.cpp dali-toolkit-test-utils/test-harness.cpp dali-toolkit-test-utils/test-gesture-generator.cpp dali-toolkit-test-utils/test-gl-abstraction.cpp diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-encoded-image-buffer.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-encoded-image-buffer.cpp new file mode 100644 index 0000000..e693098 --- /dev/null +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-encoded-image-buffer.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "test-application.h" + +#include "test-encoded-image-buffer.h" + +namespace Dali +{ +EncodedImageBuffer ConvertFileToEncodedImageBuffer(const char* url) +{ + EncodedImageBuffer buffer; + FILE *fp; + fp = fopen(url, "rb"); + if(fp != NULL) + { + fseek(fp, 0, SEEK_END); + size_t size = ftell(fp); + Dali::Vector data; + data.Resize(size); + fseek(fp, 0, SEEK_SET); + fread(data.Begin(), size, sizeof(uint8_t), fp); + fclose(fp); + buffer = EncodedImageBuffer::New(data); + } + return buffer; +} + +} // namespace Dali diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-encoded-image-buffer.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-encoded-image-buffer.h new file mode 100644 index 0000000..96fbe46 --- /dev/null +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-encoded-image-buffer.h @@ -0,0 +1,32 @@ +#ifndef TEST_ENCODED_IMAGE_BUFFER_H +#define TEST_ENCODED_IMAGE_BUFFER_H + +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include + +namespace Dali +{ + +// util function to convert local file to EncodedImageBuffer +EncodedImageBuffer ConvertFileToEncodedImageBuffer(const char* url); + +} // namespace Dali + +#endif // TEST_ENCODED_IMAGE_BUFFER_H diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Image.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Image.cpp index 37e3b5e..b4b88b6 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-Image.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-Image.cpp @@ -122,3 +122,18 @@ int UtcDaliImageConvertNativeImageSourceToUrl(void) END_TEST; } + +int UtcDaliImageConvertEncodedImageBufferToUrl(void) +{ + ToolkitTestApplication application; + tet_infoline( "UtcDaliImageConvertEncodedImageBufferToUrl" ); + + Dali::Vector buffer; + buffer.PushBack(0x11); + buffer.PushBack(0x22); + buffer.PushBack(0x33); + + DALI_TEST_CHECK( Dali::Toolkit::Image::GenerateUrl( EncodedImageBuffer::New(buffer) ).GetUrl().size() > 0u ); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp index 1cd3de5..0450040 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp @@ -28,8 +28,11 @@ #include #include #include +#include +#include #include +#include #include #include @@ -534,8 +537,6 @@ int UtcDaliImageViewAsyncLoadingWithoutAltasing(void) const std::vector& textures2 = gl.GetBoundTextures(); DALI_TEST_GREATER( textures2.size(), numTextures, TEST_LOCATION ); - - END_TEST; } @@ -713,6 +714,150 @@ int UtcDaliImageViewSyncLoading02(void) END_TEST; } +int UtcDaliImageViewAsyncLoadingEncodedBuffer(void) +{ + ToolkitTestApplication application; + TestGlAbstraction& gl = application.GetGlAbstraction(); + const std::vector& textures = gl.GetBoundTextures(); + size_t numTextures = textures.size(); + + // Get encoded raw-buffer image and generate url + EncodedImageBuffer buffer = ConvertFileToEncodedImageBuffer(gImage_600_RGB); + ImageUrl url = Toolkit::Image::GenerateUrl(buffer); + + // Async loading, no atlasing for big size image + ImageView imageView = ImageView::New(url.GetUrl()); + + // By default, Aysnc loading is used + application.GetScene().Add(imageView); + imageView.SetProperty( Actor::Property::SIZE, Vector2(100, 100) ); + imageView.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER ); + + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(16); + application.SendNotification(); + + const std::vector& textures2 = gl.GetBoundTextures(); + DALI_TEST_GREATER( textures2.size(), numTextures, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliImageViewAsyncLoadingEncodedBufferWithAtlasing(void) +{ + ToolkitTestApplication application; + + // Get encoded raw-buffer image and generate url + EncodedImageBuffer buffer = ConvertFileToEncodedImageBuffer(gImage_600_RGB); + ImageUrl url = Toolkit::Image::GenerateUrl(buffer); + ImageUrl url2 = Toolkit::Image::GenerateUrl(buffer); + + // Generate url is not equal to url2 + // NOTE : This behavior may changed when ImageUrl compare operator changed. + DALI_TEST_CHECK(url != url2); + // Generate url's string is equal to url2's string + DALI_TEST_CHECK(url.GetUrl() == url2.GetUrl()); + + EncodedImageBuffer buffer2 = ConvertFileToEncodedImageBuffer(gImage_600_RGB); + url2 = Toolkit::Image::GenerateUrl(buffer2); + + // Check whethere two url are not equal + DALI_TEST_CHECK(url.GetUrl() != url2.GetUrl()); + + // Async loading, automatic atlasing for small size image + TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace(); + callStack.Reset(); + callStack.Enable(true); + + Property::Map imageMap; + + imageMap[ ImageVisual::Property::URL ] = url.GetUrl(); + imageMap[ ImageVisual::Property::DESIRED_HEIGHT ] = 34; + imageMap[ ImageVisual::Property::DESIRED_WIDTH ] = 34; + imageMap[ ImageVisual::Property::ATLASING] = true; + + ImageView imageView = ImageView::New(); + imageView.SetProperty( ImageView::Property::IMAGE, imageMap ); + imageView.SetProperty( Toolkit::Control::Property::PADDING, Extents( 10u, 10u, 10u, 10u ) ); + + // By default, Aysnc loading is used + // loading is not started if the actor is offScene + + application.GetScene().Add( imageView ); + application.SendNotification(); + application.Render(16); + application.Render(16); + application.SendNotification(); + + // Change url to url2 + imageMap[ ImageVisual::Property::URL ] = url2.GetUrl(); + imageView.SetProperty( ImageView::Property::IMAGE, imageMap ); + + imageView.SetProperty( Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::RIGHT_TO_LEFT ); + application.SendNotification(); + application.Render(16); + application.Render(16); + application.SendNotification(); + + // loading started, this waits for the loader thread for max 30 seconds + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(16); + + callStack.Enable(false); + + TraceCallStack::NamedParams params; + params["width"] << 34; + params["height"] << 34; + DALI_TEST_EQUALS( callStack.FindMethodAndParams( "TexSubImage2D", params ), true, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliImageViewSyncLoadingEncodedBuffer(void) +{ + ToolkitTestApplication application; + + tet_infoline("ImageView Testing sync loading from EncodedImageBuffer"); + + // Get encoded raw-buffer image and generate url + EncodedImageBuffer buffer = ConvertFileToEncodedImageBuffer(gImage_34_RGBA); + ImageUrl url = Toolkit::Image::GenerateUrl(buffer); + + // Sync loading, automatic atlasing for small size image + { + TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace(); + callStack.Reset(); + callStack.Enable(true); + + ImageView imageView = ImageView::New( ); + + // Sync loading is used + Property::Map syncLoadingMap; + syncLoadingMap[ "url" ] = url.GetUrl(); + syncLoadingMap[ "desiredHeight" ] = 34; + syncLoadingMap[ "desiredWidth" ] = 34; + syncLoadingMap[ "synchronousLoading" ] = true; + syncLoadingMap[ "atlasing" ] = true; + imageView.SetProperty( ImageView::Property::IMAGE, syncLoadingMap ); + + application.GetScene().Add( imageView ); + application.SendNotification(); + application.Render(16); + + TraceCallStack::NamedParams params; + params["width"] << 34; + params["height"] << 34; + DALI_TEST_EQUALS( callStack.FindMethodAndParams( "TexSubImage2D", params ), + true, TEST_LOCATION ); + } + + END_TEST; +} + int UtcDaliImageViewAddedTexture(void) { ToolkitTestApplication application; diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp index 40ca439..1dbb737 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp @@ -24,9 +24,12 @@ #include #include #include +#include #include #include #include + +#include #include "dummy-control.h" using namespace Dali; @@ -520,6 +523,106 @@ int UtcDaliImageVisualWithNativeImageRemoved(void) END_TEST; } +int UtcDaliImageVisualWithEncodedImageBuffer(void) +{ + ToolkitTestApplication application; + tet_infoline( "Use Encoded Image Buffer as url" ); + + EncodedImageBuffer rawBuffer = ConvertFileToEncodedImageBuffer(TEST_LARGE_IMAGE_FILE_NAME); + ImageUrl url = Dali::Toolkit::Image::GenerateUrl(rawBuffer); + + VisualFactory factory = VisualFactory::Get(); + DALI_TEST_CHECK( factory ); + + Property::Map propertyMap; + propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::IMAGE ); + propertyMap.Insert( ImageVisual::Property::URL, url.GetUrl() ); + + Visual::Base visual = factory.CreateVisual( propertyMap ); + DALI_TEST_CHECK( visual ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + DummyControl actor = DummyControl::New(); + DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual ); + + actor.SetProperty( Actor::Property::SIZE, Vector2( 200.f, 200.f ) ); + DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION ); + + application.GetScene().Add( actor ); + application.SendNotification(); + + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION ); + DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION ); + + application.GetScene().Remove( actor ); + DALI_TEST_CHECK( actor.GetRendererCount() == 0u ); + + END_TEST; +} + +int UtcDaliImageVisualWithEncodedImageBufferRemoved(void) +{ + ToolkitTestApplication application; + tet_infoline( "Use Encoded Image Buffer as url" ); + + TestGlAbstraction& gl = application.GetGlAbstraction(); + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + EncodedImageBuffer rawBuffer = ConvertFileToEncodedImageBuffer(TEST_LARGE_IMAGE_FILE_NAME); + ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(rawBuffer); + std::string url = imageUrl.GetUrl(); + + VisualFactory factory = VisualFactory::Get(); + DALI_TEST_CHECK( factory ); + + Property::Map propertyMap; + propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::IMAGE ); + propertyMap.Insert( ImageVisual::Property::URL, url ); + + Visual::Base visual = factory.CreateVisual( propertyMap ); + DALI_TEST_CHECK( visual ); + + DummyControl actor = DummyControl::New(); + DummyControlImpl& dummyImpl = static_cast(actor.GetImplementation()); + dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual ); + + DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION ); + + application.GetScene().Add( actor ); + application.SendNotification(); + + // Wait for decode buffer and make texture. + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION ); + DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION ); + + tet_infoline( "Delete texture because there is no actor to use decoded texture" ); + imageUrl.Reset(); + application.GetScene().Remove( actor ); + dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL ); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION ); + DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 1, TEST_LOCATION ); + + END_TEST; +} + int UtcDaliImageVisualTextureReuse1(void) { ToolkitTestApplication application; diff --git a/dali-toolkit/devel-api/image-loader/image-atlas.h b/dali-toolkit/devel-api/image-loader/image-atlas.h index af3cc41..a1a3c49 100644 --- a/dali-toolkit/devel-api/image-loader/image-atlas.h +++ b/dali-toolkit/devel-api/image-loader/image-atlas.h @@ -1,7 +1,7 @@ #ifndef DALI_TOOLKIT_IMAGE_ATLAS_H #define DALI_TOOLKIT_IMAGE_ATLAS_H /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -157,7 +157,7 @@ public: * @param [in] size The width and height to fit the loaded image to. * @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter. * @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header. - * @param[in] atlasUploadObserver The observer to observe the upload state inside the ImageAtlas. + * @param [in] atlasUploadObserver The observer to observe the upload state inside the ImageAtlas. * @return True if there is enough space to fit this image in,false otherwise. * @note The valid callback function here is required to have the signature of void( void ). */ diff --git a/dali-toolkit/internal/image-loader/async-image-loader-impl.cpp b/dali-toolkit/internal/image-loader/async-image-loader-impl.cpp index 412eda7..ea10924 100644 --- a/dali-toolkit/internal/image-loader/async-image-loader-impl.cpp +++ b/dali-toolkit/internal/image-loader/async-image-loader-impl.cpp @@ -21,6 +21,9 @@ // EXTERNAL INCLUDES #include +// INTERNAL INCLUDES +#include + namespace Dali { namespace Toolkit @@ -71,7 +74,24 @@ uint32_t AsyncImageLoader::Load(const VisualUrl& url, mLoadThread.Start(); mIsLoadThreadStarted = true; } - mLoadThread.AddTask(new LoadingTask(++mLoadTaskId, url, dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad)); + if(url.IsBufferResource()) + { + auto visualFactory = Toolkit::VisualFactory::Get(); + if(visualFactory) + { + // Get EncodedImageBuffer from texturemanager + // and make new LoadingTask with buffer + auto& textureManager = GetImplementation(visualFactory).GetTextureManager(); + + const EncodedImageBuffer& encodedBuffer = textureManager.GetEncodedImageBuffer(url.GetUrl()); + + mLoadThread.AddTask(new LoadingTask(++mLoadTaskId, encodedBuffer, dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad)); + } + } + else + { + mLoadThread.AddTask(new LoadingTask(++mLoadTaskId, url, dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad)); + } return mLoadTaskId; } diff --git a/dali-toolkit/internal/image-loader/image-load-thread.cpp b/dali-toolkit/internal/image-loader/image-load-thread.cpp index 7fc344f..43b0707 100644 --- a/dali-toolkit/internal/image-loader/image-load-thread.cpp +++ b/dali-toolkit/internal/image-loader/image-load-thread.cpp @@ -19,6 +19,7 @@ #include "image-load-thread.h" // EXTERNAL INCLUDES +#include #include #include #include @@ -33,6 +34,7 @@ namespace Internal LoadingTask::LoadingTask(uint32_t id, Dali::AnimatedImageLoading animatedImageLoading, uint32_t frameIndex) : pixelBuffer(), url(), + encodedImageBuffer(), id(id), dimensions(), fittingMode(), @@ -51,6 +53,26 @@ LoadingTask::LoadingTask(uint32_t id, Dali::AnimatedImageLoading animatedImageLo LoadingTask::LoadingTask(uint32_t id, const VisualUrl& url, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad) : pixelBuffer(), url(url), + encodedImageBuffer(), + id(id), + dimensions(dimensions), + fittingMode(fittingMode), + samplingMode(samplingMode), + orientationCorrection(orientationCorrection), + preMultiplyOnLoad(preMultiplyOnLoad), + isMaskTask(false), + maskPixelBuffer(), + contentScale(1.0f), + cropToMask(false), + animatedImageLoading(), + frameIndex(0u) +{ +} + +LoadingTask::LoadingTask(uint32_t id, const EncodedImageBuffer& encodedImageBuffer, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad) +: pixelBuffer(), + url(), + encodedImageBuffer(encodedImageBuffer), id(id), dimensions(dimensions), fittingMode(fittingMode), @@ -69,6 +91,7 @@ LoadingTask::LoadingTask(uint32_t id, const VisualUrl& url, ImageDimensions dime LoadingTask::LoadingTask(uint32_t id, Devel::PixelBuffer pixelBuffer, Devel::PixelBuffer maskPixelBuffer, float contentScale, bool cropToMask, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad) : pixelBuffer(pixelBuffer), url(""), + encodedImageBuffer(), id(id), dimensions(), fittingMode(), @@ -90,11 +113,15 @@ void LoadingTask::Load() { pixelBuffer = animatedImageLoading.LoadFrame(frameIndex); } - else if(url.IsLocalResource()) + else if(encodedImageBuffer) + { + pixelBuffer = Dali::LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), dimensions, fittingMode, samplingMode, orientationCorrection); + } + else if(url.IsValid() && url.IsLocalResource()) { pixelBuffer = Dali::LoadImageFromFile(url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection); } - else + else if(url.IsValid()) { pixelBuffer = Dali::DownloadImageSynchronously(url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection); } diff --git a/dali-toolkit/internal/image-loader/image-load-thread.h b/dali-toolkit/internal/image-loader/image-load-thread.h index 9505b17..95ec260 100644 --- a/dali-toolkit/internal/image-loader/image-load-thread.h +++ b/dali-toolkit/internal/image-loader/image-load-thread.h @@ -29,6 +29,7 @@ #include #include #include +#include namespace Dali { @@ -72,6 +73,24 @@ struct LoadingTask /** * Constructor. * @param [in] id of the task + * @param [in] encodedImageBuffer The encoded buffer of the image to load. + * @param [in] size The width and height to fit the loaded image to, 0.0 means whole image + * @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter. + * @param [in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size. + * @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header. + * @param [in] preMultiplyOnLoad ON if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha or if the image need to be applied alpha mask. + */ + LoadingTask(uint32_t id, + const EncodedImageBuffer& encodedImageBuffer, + ImageDimensions dimensions, + FittingMode::Type fittingMode, + SamplingMode::Type samplingMode, + bool orientationCorrection, + DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad); + + /** + * Constructor. + * @param [in] id of the task * @param [in] pixelBuffer of the to be masked image * @param [in] maskPixelBuffer of the mask image * @param [in] contentScale The factor to scale the content @@ -111,6 +130,7 @@ public: Devel::PixelBuffer pixelBuffer; ///< pixelBuffer handle after successful load ///< or pixelBuffer to be masked image in the mask task VisualUrl url; ///< url of the image to load + EncodedImageBuffer encodedImageBuffer; ///< encoded buffer of the image to load uint32_t id; ///< The unique id associated with this task. ImageDimensions dimensions; ///< dimensions to load FittingMode::Type fittingMode; ///< fitting options diff --git a/dali-toolkit/internal/image-loader/image-url-impl.cpp b/dali-toolkit/internal/image-loader/image-url-impl.cpp index 055738f..52ba6c4 100644 --- a/dali-toolkit/internal/image-loader/image-url-impl.cpp +++ b/dali-toolkit/internal/image-loader/image-url-impl.cpp @@ -16,9 +16,14 @@ */ // CLASS HEADER -#include #include +// INTERNAL INCLUDES +#include +#include +#include +#include + namespace Dali { namespace Toolkit @@ -26,14 +31,39 @@ namespace Toolkit namespace Internal { ImageUrl::ImageUrl(Texture& texture) -: mUrl("") { mUrl = Dali::Toolkit::TextureManager::AddTexture(texture); } +ImageUrl::ImageUrl(const EncodedImageBuffer& encodedImageBuffer) +: mUrl("") +{ + auto visualFactory = Dali::Toolkit::VisualFactory::Get(); + if(visualFactory) + { + auto& textureManager = GetImplementation(visualFactory).GetTextureManager(); + mUrl = textureManager.AddExternalEncodedImageBuffer(encodedImageBuffer); + } +} + ImageUrl::~ImageUrl() { - Dali::Toolkit::TextureManager::RemoveTexture(mUrl); + if(mUrl.size() > 0) + { + auto visualFactory = Dali::Toolkit::VisualFactory::Get(); + if(visualFactory) + { + auto& textureManager = GetImplementation(visualFactory).GetTextureManager(); + if(VisualUrl::TEXTURE == VisualUrl::GetProtocolType(mUrl)) + { + textureManager.RemoveExternalTexture(mUrl); + } + else if(VisualUrl::BUFFER == VisualUrl::GetProtocolType(mUrl)) + { + textureManager.RemoveExternalEncodedImageBuffer(mUrl); + } + } + } } ImageUrlPtr ImageUrl::New(Texture& texture) @@ -42,6 +72,12 @@ ImageUrlPtr ImageUrl::New(Texture& texture) return imageUrlPtr; } +ImageUrlPtr ImageUrl::New(const EncodedImageBuffer& encodedImageBuffer) +{ + ImageUrlPtr imageUrlPtr = new ImageUrl(encodedImageBuffer); + return imageUrlPtr; +} + const std::string& ImageUrl::GetUrl() const { return mUrl; diff --git a/dali-toolkit/internal/image-loader/image-url-impl.h b/dali-toolkit/internal/image-loader/image-url-impl.h index 45981b2..99616bf 100644 --- a/dali-toolkit/internal/image-loader/image-url-impl.h +++ b/dali-toolkit/internal/image-loader/image-url-impl.h @@ -20,6 +20,7 @@ // EXTERNAL INCLUDES #include +#include #include // INTERNAL INCLUDES @@ -43,11 +44,21 @@ public: ImageUrl(Texture& texture); /** + * @brief Constructor. + */ + ImageUrl(const EncodedImageBuffer& encodedImageBuffer); + + /** * @copydoc Dali::Toolkit::ImageUrl::New */ static ImageUrlPtr New(Texture& texture); /** + * @copydoc Dali::Toolkit::ImageUrl::New + */ + static ImageUrlPtr New(const EncodedImageBuffer& encodedImageBuffer); + + /** * @copydoc Dali::Toolkit::ImageUrl::GetUrl */ const std::string& GetUrl() const; diff --git a/dali-toolkit/internal/visuals/image/image-visual.cpp b/dali-toolkit/internal/visuals/image/image-visual.cpp index bbbab23..16a4a4a 100644 --- a/dali-toolkit/internal/visuals/image/image-visual.cpp +++ b/dali-toolkit/internal/visuals/image/image-visual.cpp @@ -595,7 +595,7 @@ void ImageVisual::LoadTexture(bool& atlasing, Vector4& atlasRect, TextureSet& te bool ImageVisual::AttemptAtlasing() { - return (!mImpl->mCustomShader && mImageUrl.GetProtocolType() == VisualUrl::LOCAL && mAttemptAtlasing); + return (!mImpl->mCustomShader && (mImageUrl.IsLocalResource() || mImageUrl.IsBufferResource()) && mAttemptAtlasing); } void ImageVisual::InitializeRenderer() diff --git a/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp b/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp index 6ef02cc..d9c26aa 100644 --- a/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp +++ b/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp @@ -153,7 +153,7 @@ void NPatchVisual::LoadImages() TextureManager& textureManager = mFactoryCache.GetTextureManager(); bool synchronousLoading = mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING; - if(mId == NPatchData::INVALID_NPATCH_DATA_ID && mImageUrl.IsLocalResource()) + if(mId == NPatchData::INVALID_NPATCH_DATA_ID && (mImageUrl.IsLocalResource() || mImageUrl.IsBufferResource())) { bool preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader ? true : false; mId = mLoader.Load(textureManager, this, mImageUrl, mBorder, preMultiplyOnLoad, synchronousLoading); @@ -165,7 +165,7 @@ void NPatchVisual::LoadImages() } } - if(!mAuxiliaryPixelBuffer && mAuxiliaryUrl.IsValid() && mAuxiliaryUrl.IsLocalResource()) + if(!mAuxiliaryPixelBuffer && mAuxiliaryUrl.IsValid() && (mAuxiliaryUrl.IsLocalResource() || mAuxiliaryUrl.IsBufferResource())) { // Load the auxiliary image auto preMultiplyOnLoading = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY; diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.cpp b/dali-toolkit/internal/visuals/texture-manager-impl.cpp index 7ca271f..dbb1230 100644 --- a/dali-toolkit/internal/visuals/texture-manager-impl.cpp +++ b/dali-toolkit/internal/visuals/texture-manager-impl.cpp @@ -200,7 +200,18 @@ Devel::PixelBuffer TextureManager::LoadPixelBuffer( { if(url.IsValid()) { - pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection); + if(url.IsBufferResource()) + { + const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(url.GetUrl()); + if(encodedImageBuffer) + { + pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection); + } + } + else + { + pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection); + } if(pixelBuffer && preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD) { PreMultiply(pixelBuffer, preMultiplyOnLoad); @@ -245,7 +256,19 @@ TextureSet TextureManager::LoadTexture( PixelData data; if(url.IsValid()) { - Devel::PixelBuffer pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection); + Devel::PixelBuffer pixelBuffer; + if(url.IsBufferResource()) + { + const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(url.GetUrl()); + if(encodedImageBuffer) + { + pixelBuffer = LoadImageFromBuffer(encodedImageBuffer.GetRawBuffer(), desiredSize, fittingMode, samplingMode, orientationCorrection); + } + } + else + { + pixelBuffer = LoadImageFromFile(url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection); + } if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid()) { Devel::PixelBuffer maskPixelBuffer = LoadImageFromFile(maskInfo->mAlphaMaskUrl.GetUrl(), ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true); @@ -434,12 +457,35 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture id@%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId); } + // Check if the requested Texture exist in Encoded Buffer + // This mean, that buffer is not cached, and need to be decoded. + if(textureId == INVALID_TEXTURE_ID && VisualUrl::BUFFER == url.GetProtocolType()) + { + std::string location = url.GetLocation(); + if(location.size() > 0u) + { + TextureId targetId = std::stoi(location); + const EncodedImageBuffer& encodedImageBuffer = GetEncodedImageBuffer(targetId); + if(encodedImageBuffer) + { + textureId = targetId; + // Insert this buffer at mTextureInfoContainer. + // This buffer will decode at ImageLoaderThread. + bool preMultiply = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD); + mTextureInfoContainer.push_back(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex)); + cacheIndex = mTextureInfoContainer.size() - 1u; + + DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New buffered texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId); + } + } + } + if(textureId == INVALID_TEXTURE_ID) // There was no caching, or caching not required { // We need a new Texture. textureId = GenerateUniqueTextureId(); bool preMultiply = (preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD); - mTextureInfoContainer.push_back(TextureInfo(textureId, maskTextureId, url.GetUrl(), desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex)); + mTextureInfoContainer.push_back(TextureInfo(textureId, maskTextureId, url, desiredSize, contentScale, fittingMode, samplingMode, false, cropToMask, useAtlas, textureHash, orientationCorrection, preMultiply, animatedImageLoading, frameIndex)); cacheIndex = mTextureInfoContainer.size() - 1u; DALI_LOG_INFO(gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n", url.GetUrl().c_str(), observer, cacheIndex, textureId); @@ -656,6 +702,35 @@ TextureSet TextureManager::GetTextureSet(TextureId textureId) return textureSet; } +EncodedImageBuffer TextureManager::GetEncodedImageBuffer(TextureId textureId) +{ + EncodedImageBuffer encodedImageBuffer; // empty handle + for(auto&& elem : mEncodedBufferTextures) + { + if(elem.textureId == textureId) + { + encodedImageBuffer = elem.encodedImageBuffer; + break; + } + } + return encodedImageBuffer; +} + +EncodedImageBuffer TextureManager::GetEncodedImageBuffer(const std::string& url) +{ + EncodedImageBuffer encodedImageBuffer; // empty handle + if(url.size() > 0 && VisualUrl::BUFFER == VisualUrl::GetProtocolType(url)) + { + std::string location = VisualUrl::GetLocation(url); + if(location.size() > 0u) + { + TextureId targetId = std::stoi(location); + return GetEncodedImageBuffer(targetId); + } + } + return encodedImageBuffer; +} + std::string TextureManager::AddExternalTexture(TextureSet& textureSet) { TextureManager::ExternalTextureInfo info; @@ -666,13 +741,30 @@ std::string TextureManager::AddExternalTexture(TextureSet& textureSet) return VisualUrl::CreateTextureUrl(std::to_string(info.textureId)); } +std::string TextureManager::AddExternalEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer) +{ + // Duplication check + for(auto&& elem : mEncodedBufferTextures) + { + if(elem.encodedImageBuffer == encodedImageBuffer) + { + // If same buffer added, increase reference count and return. + elem.referenceCount++; + return VisualUrl::CreateBufferUrl(std::to_string(elem.textureId));; + } + } + TextureManager::EncodedBufferTextureInfo info(GenerateUniqueTextureId(), encodedImageBuffer); + mEncodedBufferTextures.emplace_back(info); + return VisualUrl::CreateBufferUrl(std::to_string(info.textureId)); +} + TextureSet TextureManager::RemoveExternalTexture(const std::string& url) { if(url.size() > 0u) { - // get the location from the Url if(VisualUrl::TEXTURE == VisualUrl::GetProtocolType(url)) { + // get the location from the Url std::string location = VisualUrl::GetLocation(url); if(location.size() > 0u) { @@ -696,7 +788,37 @@ TextureSet TextureManager::RemoveExternalTexture(const std::string& url) return TextureSet(); } -void TextureManager::UseExternalTexture(const VisualUrl& url) +EncodedImageBuffer TextureManager::RemoveExternalEncodedImageBuffer(const std::string& url) +{ + if(url.size() > 0u) + { + if(VisualUrl::BUFFER == VisualUrl::GetProtocolType(url)) + { + // get the location from the Url + std::string location = VisualUrl::GetLocation(url); + if(location.size() > 0u) + { + TextureId id = std::stoi(location); + const auto end = mEncodedBufferTextures.end(); + for(auto iter = mEncodedBufferTextures.begin(); iter != end; ++iter) + { + if(iter->textureId == id) + { + auto encodedImageBuffer = iter->encodedImageBuffer; + if(--(iter->referenceCount) <= 0) + { + mEncodedBufferTextures.erase(iter); + } + return encodedImageBuffer; + } + } + } + } + } + return EncodedImageBuffer(); +} + +void TextureManager::UseExternalResource(const VisualUrl& url) { if(VisualUrl::TEXTURE == url.GetProtocolType()) { @@ -714,6 +836,22 @@ void TextureManager::UseExternalTexture(const VisualUrl& url) } } } + else if(VisualUrl::BUFFER == url.GetProtocolType()) + { + std::string location = url.GetLocation(); + if(location.size() > 0u) + { + TextureId id = std::stoi(location); + for(auto&& elem : mEncodedBufferTextures) + { + if(elem.textureId == id) + { + elem.referenceCount++; + return; + } + } + } + } } void TextureManager::AddObserver(TextureManager::LifecycleObserver& observer) @@ -797,7 +935,7 @@ void TextureManager::LoadTexture(TextureInfo& textureInfo, TextureUploadObserver textureInfo.loadState = LoadState::LOADING; if(!textureInfo.loadSynchronously) { - auto& loadersContainer = textureInfo.url.IsLocalResource() ? mAsyncLocalLoaders : mAsyncRemoteLoaders; + auto& loadersContainer = (textureInfo.url.IsLocalResource() || textureInfo.url.IsBufferResource()) ? mAsyncLocalLoaders : mAsyncRemoteLoaders; auto loadingHelperIt = loadersContainer.GetNext(); auto premultiplyOnLoad = (textureInfo.preMultiplyOnLoad && textureInfo.maskTextureId == INVALID_TEXTURE_ID) ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF; DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End()); @@ -996,7 +1134,7 @@ void TextureManager::ApplyMask(TextureInfo& textureInfo, TextureId maskTextureId DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::ApplyMask(): url:%s sync:%s\n", textureInfo.url.GetUrl().c_str(), textureInfo.loadSynchronously ? "T" : "F"); textureInfo.loadState = LoadState::MASK_APPLYING; - auto& loadersContainer = textureInfo.url.IsLocalResource() ? mAsyncLocalLoaders : mAsyncRemoteLoaders; + auto& loadersContainer = (textureInfo.url.IsLocalResource() || textureInfo.url.IsBufferResource()) ? mAsyncLocalLoaders : mAsyncRemoteLoaders; auto loadingHelperIt = loadersContainer.GetNext(); auto premultiplyOnLoad = textureInfo.preMultiplyOnLoad ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF; DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End()); diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.h b/dali-toolkit/internal/visuals/texture-manager-impl.h index c9618a9..48eea78 100644 --- a/dali-toolkit/internal/visuals/texture-manager-impl.h +++ b/dali-toolkit/internal/visuals/texture-manager-impl.h @@ -20,6 +20,7 @@ // EXTERNAL INCLUDES #include #include +#include #include #include #include @@ -389,6 +390,20 @@ public: TextureSet GetTextureSet(TextureId textureId); /** + * @brief Get the encoded image buffer + * @param[in] textureId The textureId to look up + * @return the encoded image buffer, or an empty handle if textureId is not valid + */ + EncodedImageBuffer GetEncodedImageBuffer(TextureId textureId); + + /** + * @brief Get the encoded image buffer by VisualUrl + * @param[in] url The url to look up + * @return the encoded image buffer, or an empty handle if url is not buffer resource or buffer is not valid + */ + EncodedImageBuffer GetEncodedImageBuffer(const std::string& url); + + /** * Adds an external texture to the texture manager * @param[in] texture The texture to add * @return string containing the URL for the texture @@ -396,6 +411,13 @@ public: std::string AddExternalTexture(TextureSet& texture); /** + * Adds an external encoded image buffer to the texture manager + * @param[in] encodedImageBuffer The image buffer to add + * @return string containing the URL for the texture + */ + std::string AddExternalEncodedImageBuffer(const EncodedImageBuffer& encodedImageBuffer); + + /** * Removes an external texture from texture manager * @param[in] url The string containing the texture to remove * @return handle to the texture @@ -403,10 +425,17 @@ public: TextureSet RemoveExternalTexture(const std::string& url); /** - * @brief Notify that external textures are used. + * Removes an external encoded image buffer from texture manager + * @param[in] url The string containing the encoded image buffer to remove + * @return handle to the encoded image buffer + */ + EncodedImageBuffer RemoveExternalEncodedImageBuffer(const std::string& url); + + /** + * @brief Notify that external textures or external encoded image buffers are used. * @param[in] url The URL of the texture to use. */ - void UseExternalTexture(const VisualUrl& url); + void UseExternalResource(const VisualUrl& url); /** * Add an observer to the object. @@ -859,6 +888,20 @@ private: int16_t referenceCount{1}; }; + struct EncodedBufferTextureInfo + { + EncodedBufferTextureInfo(TextureId textureId, + const EncodedImageBuffer& encodedImageBuffer) + : textureId(textureId), + encodedImageBuffer(encodedImageBuffer), + referenceCount(1u) + { + } + TextureId textureId; + EncodedImageBuffer encodedImageBuffer; + int16_t referenceCount; + }; + private: /** * Deleted copy constructor. @@ -877,15 +920,16 @@ private: */ void ObserverDestroyed(TextureUploadObserver* observer); -private: // Member Variables: - TextureInfoContainerType mTextureInfoContainer; ///< Used to manage the life-cycle and caching of Textures - RoundRobinContainerView mAsyncLocalLoaders; ///< The Asynchronous image loaders used to provide all local async loads - RoundRobinContainerView mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads - std::vector mExternalTextures; ///< Externally provided textures - Dali::Vector mLifecycleObservers; ///< Lifecycle observers of texture manager - Dali::Vector mLoadQueue; ///< Queue of textures to load after NotifyObservers - TextureId mCurrentTextureId; ///< The current value used for the unique Texture Id generation - bool mQueueLoadFlag; ///< Flag that causes Load Textures to be queued. +private: // Member Variables: + TextureInfoContainerType mTextureInfoContainer; ///< Used to manage the life-cycle and caching of Textures + RoundRobinContainerView mAsyncLocalLoaders; ///< The Asynchronous image loaders used to provide all local async loads + RoundRobinContainerView mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads + std::vector mExternalTextures; ///< Externally provided textures + std::vector mEncodedBufferTextures; ///< Externally encoded buffer textures + Dali::Vector mLifecycleObservers; ///< Lifecycle observers of texture manager + Dali::Vector mLoadQueue; ///< Queue of textures to load after NotifyObservers + TextureId mCurrentTextureId; ///< The current value used for the unique Texture Id generation + bool mQueueLoadFlag; ///< Flag that causes Load Textures to be queued. }; } // namespace Internal diff --git a/dali-toolkit/internal/visuals/visual-url.cpp b/dali-toolkit/internal/visuals/visual-url.cpp index 1979f78..70c6dc2 100644 --- a/dali-toolkit/internal/visuals/visual-url.cpp +++ b/dali-toolkit/internal/visuals/visual-url.cpp @@ -38,15 +38,28 @@ VisualUrl::ProtocolType ResolveLocation(const std::string& url) 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]))) + // https:// or enbuf:// + const char hOre = tolower(urlCStr[0]); + const char tOrn = tolower(urlCStr[1]); + const char tOrb = tolower(urlCStr[2]); + const char pOru = tolower(urlCStr[3]); + const char sOrf = tolower(urlCStr[4]); + if(('h' == hOre) && + ('t' == tOrn) && + ('t' == tOrb) && + ('p' == pOru) && + ('s' == sOrf)) { return VisualUrl::REMOTE; } + if(('e' == hOre) && + ('n' == tOrn) && + ('b' == tOrb) && + ('u' == pOru) && + ('f' == sOrf)) + { + return VisualUrl::BUFFER; + } } else if((length > 6) && urlCStr[4] == ':' && urlCStr[5] == '/' && urlCStr[6] == '/') { @@ -73,18 +86,20 @@ VisualUrl::ProtocolType ResolveLocation(const std::string& url) else if((length > 5) && urlCStr[3] == ':' && urlCStr[4] == '/' && urlCStr[5] == '/') { // ftp:// or ssh:// - const char fOrS = tolower(urlCStr[0]); - if(('f' == fOrS) || ('s' == fOrS)) + const char fOrs = tolower(urlCStr[0]); + const char tOrs = tolower(urlCStr[1]); + const char pOrh = tolower(urlCStr[2]); + if(('f' == fOrs) && + ('t' == tOrs) && + ('p' == pOrh)) { - const char tOrs = tolower(urlCStr[1]); - if(('t' == tOrs) || ('s' == tOrs)) - { - const char pOrh = tolower(urlCStr[2]); - if(('p' == pOrh) || ('h' == pOrh)) - { - return VisualUrl::REMOTE; - } - } + return VisualUrl::REMOTE; + } + if(('s' == fOrs) && + ('s' == tOrs) && + ('h' == pOrh)) + { + return VisualUrl::REMOTE; } } return VisualUrl::LOCAL; @@ -208,9 +223,9 @@ VisualUrl::VisualUrl(const std::string& url) if(!url.empty()) { mLocation = ResolveLocation(url); - if(VisualUrl::TEXTURE != mLocation) + if(VisualUrl::TEXTURE != mLocation && VisualUrl::BUFFER != mLocation) { - // TEXTURE location url doesn't need type resolving, REGULAR_IMAGE is fine + // TEXTURE and BUFFER location url doesn't need type resolving, REGULAR_IMAGE is fine mType = ResolveType(url); } else @@ -218,7 +233,7 @@ VisualUrl::VisualUrl(const std::string& url) Toolkit::VisualFactory factory = Toolkit::VisualFactory::Get(); if(factory) { - GetImplementation(factory).GetTextureManager().UseExternalTexture(*this); + GetImplementation(factory).GetTextureManager().UseExternalResource(*this); } } } @@ -229,12 +244,12 @@ VisualUrl::VisualUrl(const VisualUrl& url) mType(url.mType), mLocation(url.mLocation) { - if(VisualUrl::TEXTURE == mLocation) + if(VisualUrl::TEXTURE == mLocation || VisualUrl::BUFFER == mLocation) { Toolkit::VisualFactory factory = Toolkit::VisualFactory::Get(); if(factory) { - GetImplementation(factory).GetTextureManager().UseExternalTexture(*this); + GetImplementation(factory).GetTextureManager().UseExternalResource(*this); } } } @@ -249,6 +264,14 @@ VisualUrl::~VisualUrl() GetImplementation(factory).GetTextureManager().RemoveExternalTexture(mUrl); } } + else if(VisualUrl::BUFFER == mLocation) + { + Toolkit::VisualFactory factory = Toolkit::VisualFactory::Get(); + if(factory) + { + GetImplementation(factory).GetTextureManager().RemoveExternalEncodedImageBuffer(mUrl); + } + } } VisualUrl& VisualUrl::operator=(const VisualUrl& url) @@ -263,17 +286,25 @@ VisualUrl& VisualUrl::operator=(const VisualUrl& url) GetImplementation(factory).GetTextureManager().RemoveExternalTexture(mUrl); } } + else if(VisualUrl::BUFFER == mLocation) + { + Toolkit::VisualFactory factory = Toolkit::VisualFactory::Get(); + if(factory) + { + GetImplementation(factory).GetTextureManager().RemoveExternalEncodedImageBuffer(mUrl); + } + } mUrl = url.mUrl; mType = url.mType; mLocation = url.mLocation; - if(VisualUrl::TEXTURE == mLocation) + if(VisualUrl::TEXTURE == mLocation || VisualUrl::BUFFER == mLocation) { Toolkit::VisualFactory factory = Toolkit::VisualFactory::Get(); if(factory) { - GetImplementation(factory).GetTextureManager().UseExternalTexture(*this); + GetImplementation(factory).GetTextureManager().UseExternalResource(*this); } } } @@ -305,6 +336,11 @@ bool VisualUrl::IsLocalResource() const return mLocation == VisualUrl::LOCAL; } +bool VisualUrl::IsBufferResource() const +{ + return mLocation == VisualUrl::BUFFER; +} + std::string VisualUrl::GetLocation() const { return GetLocation(mUrl); @@ -315,6 +351,11 @@ std::string VisualUrl::CreateTextureUrl(const std::string& location) return "dali://" + location; } +std::string VisualUrl::CreateBufferUrl(const std::string& location) +{ + return "enbuf://" + location; +} + VisualUrl::ProtocolType VisualUrl::GetProtocolType(const std::string& url) { return ResolveLocation(url); @@ -330,7 +371,6 @@ std::string VisualUrl::GetLocation(const std::string& url) return url; } - } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/visuals/visual-url.h b/dali-toolkit/internal/visuals/visual-url.h index a772bd1..555e383 100644 --- a/dali-toolkit/internal/visuals/visual-url.h +++ b/dali-toolkit/internal/visuals/visual-url.h @@ -45,7 +45,8 @@ public: { LOCAL, ///< file in local file system TEXTURE, ///< texture uploaded to texture manager - REMOTE ///< remote image + REMOTE, ///< remote image + BUFFER ///< encoded image buffer }; /** @@ -111,6 +112,11 @@ public: bool IsLocalResource() const; /** + * @return true if the location is BUFFER, i.e. may contain EncodedImageBuffer + */ + bool IsBufferResource() const; + + /** * @return the location part of the url */ std::string GetLocation() const; @@ -123,6 +129,13 @@ public: static std::string CreateTextureUrl(const std::string& location); /** + * Helper to create a URL of type BUFFER + * @param location the location of the texture + * @return the Url + */ + static std::string CreateBufferUrl(const std::string& location); + + /** * Helper to get a ProtocolType from url * @param url the url of the texture * @return the protocol type @@ -135,6 +148,7 @@ public: * @return the location */ static std::string GetLocation(const std::string& url); + private: std::string mUrl; Type mType; diff --git a/dali-toolkit/public-api/image-loader/image-url.cpp b/dali-toolkit/public-api/image-loader/image-url.cpp index 65b9601..f936fdc 100644 --- a/dali-toolkit/public-api/image-loader/image-url.cpp +++ b/dali-toolkit/public-api/image-loader/image-url.cpp @@ -38,6 +38,12 @@ ImageUrl ImageUrl::New(Texture& texture) return ImageUrl(internal.Get()); } +ImageUrl ImageUrl::New(const EncodedImageBuffer& encodedImageBuffer) +{ + Toolkit::Internal::ImageUrlPtr internal = Toolkit::Internal::ImageUrl::New(encodedImageBuffer); + return ImageUrl(internal.Get()); +} + ImageUrl ImageUrl::DownCast(BaseHandle handle) { return ImageUrl(dynamic_cast(handle.GetObjectPtr())); diff --git a/dali-toolkit/public-api/image-loader/image-url.h b/dali-toolkit/public-api/image-loader/image-url.h index 819198b..976f179 100644 --- a/dali-toolkit/public-api/image-loader/image-url.h +++ b/dali-toolkit/public-api/image-loader/image-url.h @@ -20,6 +20,7 @@ // EXTERNAL INCLUDES #include #include +#include // INTERNAL INCLUDES #include @@ -39,6 +40,7 @@ class ImageUrl; * Application can get url from ImageUrl. * When application does not use this anymore, the destructor of the ImageUrl is called. * At this time, the buffer is deleted from the texture manager. + * @note Visual also have reference of the buffer. In this case, buffer will be deleted after visual is deleted. */ class DALI_TOOLKIT_API ImageUrl : public BaseHandle { @@ -63,6 +65,14 @@ public: static ImageUrl New(Texture& texture); /** + * @brief Create an initialized ImageUrl. + * + * @param[in] encodedImageBuffer The encoded image buffer url is got from external buffer. + * @return A handle to a newly allocated Dali resource. + */ + static ImageUrl New(const EncodedImageBuffer& encodedImageBuffer); + + /** * @brief Downcast an Object handle to ImageUrl handle. * * If handle points to a ImageUrl object the downcast produces valid diff --git a/dali-toolkit/public-api/image-loader/image.cpp b/dali-toolkit/public-api/image-loader/image.cpp index b44061e..7b91059 100644 --- a/dali-toolkit/public-api/image-loader/image.cpp +++ b/dali-toolkit/public-api/image-loader/image.cpp @@ -60,6 +60,11 @@ Dali::Toolkit::ImageUrl GenerateUrl(const Dali::NativeImageSourcePtr nativeImage return imageUrl; } +Dali::Toolkit::ImageUrl GenerateUrl(const Dali::EncodedImageBuffer encodedImageBuffer) +{ + return Dali::Toolkit::ImageUrl::New(encodedImageBuffer); +} + } // namespace Image } // namespace Toolkit diff --git a/dali-toolkit/public-api/image-loader/image.h b/dali-toolkit/public-api/image-loader/image.h index ad2f56e..6db6e7e 100644 --- a/dali-toolkit/public-api/image-loader/image.h +++ b/dali-toolkit/public-api/image-loader/image.h @@ -19,6 +19,7 @@ // EXTERNAL INCLUDES #include +#include #include #include @@ -78,6 +79,15 @@ DALI_TOOLKIT_API Dali::Toolkit::ImageUrl GenerateUrl(const Dali::PixelData pixel */ DALI_TOOLKIT_API Dali::Toolkit::ImageUrl GenerateUrl(const Dali::NativeImageSourcePtr nativeImageSource); +/** + * @brief Generate a Url from encoded image buffer. + * This Url can be used in visuals to render the image. + * @note This method does not check for duplicates, If same encoded image buffer is entered multiple times, a different URL is returned each time. + * @param[in] encodedImageBuffer the encoded image buffer to converted to Url + * @return the ImageUrl representing this encoded image buffer + */ +DALI_TOOLKIT_API Dali::Toolkit::ImageUrl GenerateUrl(const Dali::EncodedImageBuffer encodedImageBuffer); + } // namespace Image } // namespace Toolkit -- 2.7.4