From: Richard Huang Date: Fri, 27 Nov 2020 11:57:59 +0000 (+0000) Subject: [dali_2.0.3] Merge branch 'devel/master' X-Git-Tag: dali_2.0.7~4^2~3 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=10f0460155a75c3829242df27171a4f3161385b1;hp=812b7095b1b28a24e1e561dfa0b50a4ee613884d [dali_2.0.3] Merge branch 'devel/master' Change-Id: I76b99bd86b1793f1c8c7d4950005bb227ddfca01 --- diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.h index 2c1c703..b8de978 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.h +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.h @@ -378,6 +378,34 @@ inline void DALI_TEST_PRINT_ASSERT(DaliException& e) DALI_TEST_ASSERT(e, assertstring, TEST_LOCATION); \ } +/** + * Test that given piece of code triggers an exception + * Fails the test if the exception didn't occur. + * Turns off logging during the execution of the code to avoid excessive false positive log output from the assertions + * @param expressions code to execute + * @param except the exception expected in the assert + */ +#define DALI_TEST_THROWS(expressions, except) \ + try \ + { \ + TestApplication::EnableLogging(false); \ + expressions; \ + TestApplication::EnableLogging(true); \ + fprintf(stderr, "Test failed in %s, expected exception: '%s' didn't occur\n", __FILELINE__, #except); \ + tet_result(TET_FAIL); \ + throw("TET_FAIL"); \ + } \ + catch(except &) \ + { \ + tet_result(TET_PASS); \ + } \ + catch(...) \ + { \ + fprintf(stderr, "Test failed in %s, unexpected exception\n", __FILELINE__); \ + tet_result(TET_FAIL); \ + throw; \ + } + // Functor to test whether an Applied signal is emitted struct ConstraintAppliedCheck { diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-scene-holder-impl.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-scene-holder-impl.h index 203ac73..86b3bd9 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-scene-holder-impl.h +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-scene-holder-impl.h @@ -67,6 +67,8 @@ public: Integration::StencilBufferAvailable GetStencilBufferRequired() override { return Integration::StencilBufferAvailable::FALSE; }; + int GetOrientation() const override {return 0;}; + void SetBackgroundColor( Vector4 color ) {}; Vector4 GetBackgroundColor() { return Color::WHITE; }; diff --git a/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp b/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp index faae3fe..db708c1 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp @@ -984,7 +984,7 @@ int UtcDaliVisualFactoryGetNPatchVisual7(void) END_TEST; } -int UtcDaliNPatchVisualAuxiliaryImage(void) +int UtcDaliNPatchVisualAuxiliaryImage01(void) { ToolkitTestApplication application; tet_infoline( "NPatchVisual with aux image" ); @@ -1034,6 +1034,38 @@ int UtcDaliNPatchVisualAuxiliaryImage(void) END_TEST; } +int UtcDaliNPatchVisualAuxiliaryImage02(void) +{ + ToolkitTestApplication application; + tet_infoline( "Multiple NPatchVisual with aux image coincidentally" ); + + const Property::Value NPATCH_TEST{ + {ImageVisual::Property::URL, TEST_9_PATCH_FILE_NAME}, + {DevelImageVisual::Property::AUXILIARY_IMAGE, TEST_AUX_IMAGE}}; + + ImageView imageView1 = ImageView::New(); + imageView1[ImageView::Property::IMAGE] = NPATCH_TEST; + application.GetScene().Add( imageView1 ); + + ImageView imageView2 = ImageView::New(); + imageView2[ImageView::Property::IMAGE] = NPATCH_TEST; + application.GetScene().Add( imageView2 ); + + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 3 ), true, TEST_LOCATION ); + + application.SendNotification(); + application.Render(); + + Renderer renderer1 = imageView1.GetRendererAt( 0 ); + auto textureSet1 = renderer1.GetTextures(); + + Renderer renderer2 = imageView2.GetRendererAt( 0 ); + auto textureSet2 = renderer2.GetTextures(); + DALI_TEST_EQUALS( textureSet1 == textureSet2, true, TEST_LOCATION ); + + END_TEST; +} + int UtcDaliVisualFactoryGetNPatchVisualN1(void) { diff --git a/dali-toolkit/internal/text/markup-processor.cpp b/dali-toolkit/internal/text/markup-processor.cpp index dac4f92..8e0b85b 100755 --- a/dali-toolkit/internal/text/markup-processor.cpp +++ b/dali-toolkit/internal/text/markup-processor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ // EXTERNAL INCLUDES #include // for ULONG_MAX +#include #include // INTERNAL INCLUDES @@ -145,6 +146,17 @@ void Initialize( FontDescriptionRun& fontRun ) } /** + * @brief Initializes a color run description to its defaults. + * + * @param[in,out] colorRun The font description run to initialize. + */ +void Initialize( ColorRun& colorRun ) +{ + colorRun.characterRun.characterIndex = 0u; + colorRun.characterRun.numberOfCharacters = 0u; +} + +/** * @brief Splits the tag string into the tag name and its attributes. * * The attributes are stored in a vector in the tag. @@ -486,6 +498,203 @@ bool XHTMLNumericEntityToUtf8 ( const char* markupText, char* utf8 ) return result; } +/** + * @brief Processes a particular tag for the required run (color-run or font-run). + * + * @tparam RunType Whether ColorRun or FontDescriptionRun + * + * @param[in/out] runsContainer The container containing all the runs + * @param[in/out] styleStack The style stack + * @param[in] tag The tag we are currently processing + * @param[in] characterIndex The current character index + * @param[in/out] runIndex The run index + * @param[in/out] tagReference The tagReference we should increment/decrement + * @param[in] parameterSettingFunction This function will be called to set run specific parameters + */ +template +void ProcessTagForRun( + Vector& runsContainer, + StyleStack& styleStack, + const Tag& tag, + const CharacterIndex characterIndex, + StyleStack::RunIndex& runIndex, + int& tagReference, + std::function parameterSettingFunction) +{ + if( !tag.isEndTag ) + { + // Create a new run. + RunType run; + Initialize(run); + + // Fill the run with the parameters. + run.characterRun.characterIndex = characterIndex; + parameterSettingFunction(tag, run); + + // Push the run in the logical model. + runsContainer.PushBack(run); + + // Push the index of the run into the stack. + styleStack.Push(runIndex); + + // Point the next free run. + ++runIndex; + + // Increase reference + ++tagReference; + } + else + { + if( tagReference > 0 ) + { + // Pop the top of the stack and set the number of characters of the run. + RunType& run = *( runsContainer.Begin() + styleStack.Pop() ); + run.characterRun.numberOfCharacters = characterIndex - run.characterRun.characterIndex; + --tagReference; + } + } +} + +/** + * @brief Processes the item tag + * + * @param[in/out] markupProcessData The markup process data + * @param[in] tag The current tag + * @param[in/out] characterIndex The current character index + */ +void ProcessItemTag( + MarkupProcessData& markupProcessData, + const Tag tag, + CharacterIndex& characterIndex) +{ + if (tag.isEndTag) + { + // Create an embedded item instance. + EmbeddedItem item; + item.characterIndex = characterIndex; + ProcessEmbeddedItem(tag, item); + + markupProcessData.items.PushBack(item); + + // Insert white space character that will be replaced by the item. + markupProcessData.markupProcessedText.append( 1u, WHITE_SPACE ); + ++characterIndex; + } +} + +/** + * @brief Resizes the model's vectors + * + * @param[in/out] markupProcessData The markup process data + * @param[in] fontRunIndex The font run index + * @param[in] colorRunIndex The color run index + */ +void ResizeModelVectors(MarkupProcessData& markupProcessData, const StyleStack::RunIndex fontRunIndex, const StyleStack::RunIndex colorRunIndex) +{ + markupProcessData.fontRuns.Resize( fontRunIndex ); + markupProcessData.colorRuns.Resize( colorRunIndex ); + +#ifdef DEBUG_ENABLED + for( unsigned int i=0; i or & special character. + const unsigned char nextCharacter = *( markupStringBuffer + 1u ); + if( ( LESS_THAN == nextCharacter ) || ( GREATER_THAN == nextCharacter ) || ( AMPERSAND == nextCharacter ) ) + { + character = nextCharacter; + ++markupStringBuffer; + + count = GetUtf8Length( character ); + markupBuffer = markupStringBuffer; + } + } + else // checking if contains XHTML entity or not + { + const unsigned int len = GetXHTMLEntityLength( markupStringBuffer, markupStringEndBuffer); + + // Parse markupStringTxt if it contains XHTML Entity between '&' and ';' + if( len > 0 ) + { + char* entityCode = NULL; + bool result = false; + count = 0; + + // Checking if XHTML Numeric Entity + if( HASH == *( markupBuffer + 1u ) ) + { + entityCode = &utf8[0]; + // markupBuffer is currently pointing to '&'. By adding 2u to markupBuffer it will point to numeric string by skipping "&#' + result = XHTMLNumericEntityToUtf8( ( markupBuffer + 2u ), entityCode ); + } + else // Checking if XHTML Named Entity + { + entityCode = const_cast ( NamedEntityToUtf8( markupBuffer, len ) ); + result = ( entityCode != NULL ); + } + if ( result ) + { + markupBuffer = entityCode; //utf8 text assigned to markupBuffer + character = markupBuffer[0]; + } + else + { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Not valid XHTML entity : (%.*s) \n", len, markupBuffer ); + markupBuffer = NULL; + } + } + else // in case string conatins Start of XHTML Entity('&') but not its end character(';') + { + if( character == AMPERSAND ) + { + markupBuffer = NULL; + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Not Well formed XHTML content \n" ); + } + } + } + + if( markupBuffer != NULL ) + { + const unsigned char numberOfBytes = GetUtf8Length( character ); + markupProcessData.markupProcessedText.push_back( character ); + + for( unsigned char i = 1u; i < numberOfBytes; ++i ) + { + ++markupBuffer; + markupProcessData.markupProcessedText.push_back( *markupBuffer ); + } + + ++characterIndex; + markupStringBuffer += count; + } +} + } // namespace void ProcessMarkupString( const std::string& markupString, MarkupProcessData& markupProcessData ) @@ -528,317 +737,69 @@ void ProcessMarkupString( const std::string& markupString, MarkupProcessData& ma { if( TokenComparison( XHTML_COLOR_TAG, tag.buffer, tag.length ) ) { - if( !tag.isEndTag ) - { - // Create a new color run. - ColorRun colorRun; - colorRun.characterRun.numberOfCharacters = 0u; - - // Set the start character index. - colorRun.characterRun.characterIndex = characterIndex; - - // Fill the run with the attributes. - ProcessColorTag( tag, colorRun ); - - // Push the color run in the logical model. - markupProcessData.colorRuns.PushBack( colorRun ); - - // Push the index of the run into the stack. - styleStack.Push( colorRunIndex ); - - // Point the next color run. - ++colorRunIndex; - - // Increase reference - ++colorTagReference; - } - else - { - if( colorTagReference > 0 ) - { - // Pop the top of the stack and set the number of characters of the run. - ColorRun& colorRun = *( markupProcessData.colorRuns.Begin() + styleStack.Pop() ); - colorRun.characterRun.numberOfCharacters = characterIndex - colorRun.characterRun.characterIndex; - --colorTagReference; - } - } + ProcessTagForRun( + markupProcessData.colorRuns, styleStack, tag, characterIndex, colorRunIndex, colorTagReference, + [] (const Tag& tag, ColorRun& run) { ProcessColorTag( tag, run ); }); } // else if( TokenComparison( XHTML_I_TAG, tag.buffer, tag.length ) ) { - if( !tag.isEndTag ) - { - // Create a new font run. - FontDescriptionRun fontRun; - Initialize( fontRun ); - - // Fill the run with the parameters. - fontRun.characterRun.characterIndex = characterIndex; - fontRun.slant = TextAbstraction::FontSlant::ITALIC; - fontRun.slantDefined = true; - - // Push the font run in the logical model. - markupProcessData.fontRuns.PushBack( fontRun ); - - // Push the index of the run into the stack. - styleStack.Push( fontRunIndex ); - - // Point the next free font run. - ++fontRunIndex; - - // Increase reference - ++iTagReference; - } - else - { - if( iTagReference > 0 ) - { - // Pop the top of the stack and set the number of characters of the run. - FontDescriptionRun& fontRun = *( markupProcessData.fontRuns.Begin() + styleStack.Pop() ); - fontRun.characterRun.numberOfCharacters = characterIndex - fontRun.characterRun.characterIndex; - --iTagReference; - } - } + ProcessTagForRun( + markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, iTagReference, + [] (const Tag&, FontDescriptionRun& fontRun) + { + fontRun.slant = TextAbstraction::FontSlant::ITALIC; + fontRun.slantDefined = true; + }); } // else if( TokenComparison( XHTML_U_TAG, tag.buffer, tag.length ) ) { - if( !tag.isEndTag ) - { - // Create a new underline run. - } - else - { - // Pop the top of the stack and set the number of characters of the run. - } + // TODO: If !tag.isEndTag, then create a new underline run. + // else Pop the top of the stack and set the number of characters of the run. } // else if( TokenComparison( XHTML_B_TAG, tag.buffer, tag.length ) ) { - if( !tag.isEndTag ) - { - // Create a new font run. - FontDescriptionRun fontRun; - Initialize( fontRun ); - - // Fill the run with the parameters. - fontRun.characterRun.characterIndex = characterIndex; - fontRun.weight = TextAbstraction::FontWeight::BOLD; - fontRun.weightDefined = true; - - // Push the font run in the logical model. - markupProcessData.fontRuns.PushBack( fontRun ); - - // Push the index of the run into the stack. - styleStack.Push( fontRunIndex ); - - // Point the next free font run. - ++fontRunIndex; - - // Increase reference - ++bTagReference; - } - else - { - if( bTagReference > 0 ) - { - // Pop the top of the stack and set the number of characters of the run. - FontDescriptionRun& fontRun = *( markupProcessData.fontRuns.Begin() + styleStack.Pop() ); - fontRun.characterRun.numberOfCharacters = characterIndex - fontRun.characterRun.characterIndex; - --bTagReference; - } - } + ProcessTagForRun( + markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, bTagReference, + [] (const Tag&, FontDescriptionRun& fontRun) + { + fontRun.weight = TextAbstraction::FontWeight::BOLD; + fontRun.weightDefined = true; + }); } // else if( TokenComparison( XHTML_FONT_TAG, tag.buffer, tag.length ) ) { - if( !tag.isEndTag ) - { - // Create a new font run. - FontDescriptionRun fontRun; - Initialize( fontRun ); - - // Fill the run with the parameters. - fontRun.characterRun.characterIndex = characterIndex; - - ProcessFontTag( tag, fontRun ); - - // Push the font run in the logical model. - markupProcessData.fontRuns.PushBack( fontRun ); - - // Push the index of the run into the stack. - styleStack.Push( fontRunIndex ); - - // Point the next free font run. - ++fontRunIndex; - - // Increase reference - ++fontTagReference; - } - else - { - if( fontTagReference > 0 ) - { - // Pop the top of the stack and set the number of characters of the run. - FontDescriptionRun& fontRun = *( markupProcessData.fontRuns.Begin() + styleStack.Pop() ); - fontRun.characterRun.numberOfCharacters = characterIndex - fontRun.characterRun.characterIndex; - --fontTagReference; - } - } + ProcessTagForRun( + markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, fontTagReference, + [] (const Tag& tag, FontDescriptionRun& fontRun) { ProcessFontTag( tag, fontRun ); }); } // else if( TokenComparison( XHTML_SHADOW_TAG, tag.buffer, tag.length ) ) { - if( !tag.isEndTag ) - { - // Create a new shadow run. - } - else - { - // Pop the top of the stack and set the number of characters of the run. - } + // TODO: If !tag.isEndTag, then create a new shadow run. + // else Pop the top of the stack and set the number of characters of the run. } // else if( TokenComparison( XHTML_GLOW_TAG, tag.buffer, tag.length ) ) { - if( !tag.isEndTag ) - { - // Create a new glow run. - } - else - { - // Pop the top of the stack and set the number of characters of the run. - } + // TODO: If !tag.isEndTag, then create a new glow run. + // else Pop the top of the stack and set the number of characters of the run. } // else if( TokenComparison( XHTML_OUTLINE_TAG, tag.buffer, tag.length ) ) { - if( !tag.isEndTag ) - { - // Create a new outline run. - } - else - { - // Pop the top of the stack and set the number of characters of the run. - } + // TODO: If !tag.isEndTag, then create a new outline run. + // else Pop the top of the stack and set the number of characters of the run. } // else if (TokenComparison(XHTML_ITEM_TAG, tag.buffer, tag.length)) { - if (tag.isEndTag) - { - // Create an embedded item instance. - EmbeddedItem item; - item.characterIndex = characterIndex; - ProcessEmbeddedItem(tag, item); - - markupProcessData.items.PushBack(item); - - // Insert white space character that will be replaced by the item. - markupProcessData.markupProcessedText.append( 1u, WHITE_SPACE ); - ++characterIndex; - } + ProcessItemTag(markupProcessData, tag, characterIndex); } } // end if( IsTag() ) else if( markupStringBuffer < markupStringEndBuffer ) { - unsigned char character = *markupStringBuffer; - const char* markupBuffer = markupStringBuffer; - unsigned char count = GetUtf8Length( character ); - char utf8[8]; - - if( ( BACK_SLASH == character ) && ( markupStringBuffer + 1u < markupStringEndBuffer ) ) - { - // Adding < , > or & special character. - const unsigned char nextCharacter = *( markupStringBuffer + 1u ); - if( ( LESS_THAN == nextCharacter ) || ( GREATER_THAN == nextCharacter ) || ( AMPERSAND == nextCharacter ) ) - { - character = nextCharacter; - ++markupStringBuffer; - - count = GetUtf8Length( character ); - markupBuffer = markupStringBuffer; - } - } - else // checking if conatins XHTML entity or not - { - const unsigned int len = GetXHTMLEntityLength( markupStringBuffer, markupStringEndBuffer); - - // Parse markupStringTxt if it contains XHTML Entity between '&' and ';' - if( len > 0 ) - { - char* entityCode = NULL; - bool result = false; - count = 0; - - // Checking if XHTML Numeric Entity - if( HASH == *( markupBuffer + 1u ) ) - { - entityCode = &utf8[0]; - // markupBuffer is currently pointing to '&'. By adding 2u to markupBuffer it will point to numeric string by skipping "&#' - result = XHTMLNumericEntityToUtf8( ( markupBuffer + 2u ), entityCode ); - } - else // Checking if XHTML Named Entity - { - entityCode = const_cast ( NamedEntityToUtf8( markupBuffer, len ) ); - result = ( entityCode != NULL ); - } - if ( result ) - { - markupBuffer = entityCode; //utf8 text assigned to markupBuffer - character = markupBuffer[0]; - } - else - { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Not valid XHTML entity : (%.*s) \n", len, markupBuffer ); - markupBuffer = NULL; - } - } - else // in case string conatins Start of XHTML Entity('&') but not its end character(';') - { - if( character == AMPERSAND ) - { - markupBuffer = NULL; - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Not Well formed XHTML content \n" ); - } - } - } - - if( markupBuffer != NULL ) - { - const unsigned char numberOfBytes = GetUtf8Length( character ); - markupProcessData.markupProcessedText.push_back( character ); - - for( unsigned char i = 1u; i < numberOfBytes; ++i ) - { - ++markupBuffer; - markupProcessData.markupProcessedText.push_back( *markupBuffer ); - } - - ++characterIndex; - markupStringBuffer += count; - } + ProcessMarkupStringBuffer(markupProcessData, markupStringBuffer, markupStringEndBuffer, characterIndex); } } // Resize the model's vectors. - if( 0u == fontRunIndex ) - { - markupProcessData.fontRuns.Clear(); - } - else - { - markupProcessData.fontRuns.Resize( fontRunIndex ); - } - - if( 0u == colorRunIndex ) - { - markupProcessData.colorRuns.Clear(); - } - else - { - markupProcessData.colorRuns.Resize( colorRunIndex ); - -#ifdef DEBUG_ENABLED - for( unsigned int i=0; iobserverList.PushBack( textureObserver ); data = mCache[ index ]; - cachedIndex = index + 1u; // valid indices are from 1 onwards - break; + return index + 1u; // valid indices are from 1 onwards } else { @@ -176,14 +176,25 @@ std::size_t NPatchLoader::Load( TextureManager& textureManager, TextureUploadObs return cachedIndex; } -void NPatchLoader::SetNPatchData( std::size_t id, Devel::PixelBuffer& pixelBuffer ) +void NPatchLoader::SetNPatchData( bool loadSuccess, std::size_t id, Devel::PixelBuffer& pixelBuffer, const Internal::VisualUrl& url, bool preMultiplied ) { Data* data; data = mCache[ id - 1u ]; - if( !data->loadCompleted ) + // To prevent recursion. + // data->loadCompleted will be set true in the NPatchBuffer::SetLoadedNPatchData when the first observer called this method. + if( data->loadCompleted ) { - NPatchBuffer::SetLoadedNPatchData( data, pixelBuffer ); + return; + } + + NPatchBuffer::SetLoadedNPatchData( data, pixelBuffer ); + + while( data->observerList.Count() ) + { + TextureUploadObserver* observer = data->observerList[0]; + observer->LoadComplete( loadSuccess, Devel::PixelBuffer(), url, preMultiplied ); + data->observerList.Erase( data->observerList.begin() ); } } diff --git a/dali-toolkit/internal/visuals/npatch-loader.h b/dali-toolkit/internal/visuals/npatch-loader.h index 2c0e852..a3aa464 100644 --- a/dali-toolkit/internal/visuals/npatch-loader.h +++ b/dali-toolkit/internal/visuals/npatch-loader.h @@ -69,6 +69,9 @@ public: ~Data(); + using ObserverListType = Dali::Vector< TextureUploadObserver* >; + + ObserverListType observerList; ///< Container used to store all observer clients of this Texture std::string url; ///< Url of the N-Patch TextureSet textureSet; ///< Texture containing the cropped image NPatchUtility::StretchRanges stretchPixelsX; ///< X stretch pixels @@ -110,10 +113,13 @@ public: /** * @brief Set loaded PixelBuffer and its information * + * @param [in] loadSuccess True if the texture load was successful (i.e. the resource is available). If false, then the resource failed to load. * @param [in] id cache data id * @param [in] pixelBuffer of loaded image + * @param [in] url The url address of the loaded image. + * @param [in] preMultiplied True if the image had pre-multiplied alpha applied */ - void SetNPatchData( std::size_t id, Devel::PixelBuffer& pixelBuffer ); + void SetNPatchData( bool loadSuccess, std::size_t id, Devel::PixelBuffer& pixelBuffer, const Internal::VisualUrl& url, bool preMultiplied ); /** * @brief Retrieve N patch data matching to an id diff --git a/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp b/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp index bd374aa..5c03ac2 100644 --- a/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp +++ b/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp @@ -873,11 +873,17 @@ void NPatchVisual::LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffe } else { + Devel::PixelBuffer loadedPixelBuffer; if( loadSuccess ) { - mLoader.SetNPatchData( mId, pixelBuffer ); + loadedPixelBuffer = pixelBuffer; EnablePreMultipliedAlpha( preMultiplied ); } + else + { + loadedPixelBuffer = LoadImageFromFile( mFactoryCache.GetTextureManager().GetBrokenImageUrl() ); + } + mLoader.SetNPatchData( loadSuccess, mId, loadedPixelBuffer, url, preMultiplied ); if( mAuxiliaryPixelBuffer || !mAuxiliaryUrl.IsValid() ) { diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.cpp b/dali-toolkit/internal/visuals/texture-manager-impl.cpp index 00b8eca..2d82b41 100644 --- a/dali-toolkit/internal/visuals/texture-manager-impl.cpp +++ b/dali-toolkit/internal/visuals/texture-manager-impl.cpp @@ -38,6 +38,7 @@ namespace { +constexpr auto INITIAL_CACHE_NUMBER = size_t{0u}; constexpr auto DEFAULT_NUMBER_OF_LOCAL_LOADER_THREADS = size_t{4u}; constexpr auto DEFAULT_NUMBER_OF_REMOTE_LOADER_THREADS = size_t{8u}; @@ -454,13 +455,18 @@ TextureManager::TextureId TextureManager::RequestLoadInternal( { // First check if the requested Texture is cached. bool isAnimatedImage = ( animatedImageLoading ) ? true : false; - const TextureHash textureHash = GenerateHash( url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, - maskTextureId, storageType, isAnimatedImage, frameIndex ); + + TextureHash textureHash = INITIAL_CACHE_NUMBER; + int cacheIndex = INVALID_CACHE_INDEX; + if(storageType != StorageType::RETURN_PIXEL_BUFFER) + { + textureHash = GenerateHash(url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, isAnimatedImage, frameIndex); + + // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision. + cacheIndex = FindCachedTexture(textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, maskTextureId, preMultiplyOnLoad, isAnimatedImage, frameIndex); + } TextureManager::TextureId textureId = INVALID_TEXTURE_ID; - // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision. - int cacheIndex = FindCachedTexture( textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas, - maskTextureId, preMultiplyOnLoad, storageType, isAnimatedImage, frameIndex ); // Check if the requested Texture exists in the cache. if( cacheIndex != INVALID_CACHE_INDEX ) @@ -1170,7 +1176,6 @@ TextureManager::TextureHash TextureManager::GenerateHash( const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas, TextureId maskTextureId, - StorageType storageType, bool isAnimationImage, uint32_t frameIndex ) { @@ -1193,8 +1198,8 @@ TextureManager::TextureHash TextureManager::GenerateHash( *hashTargetPtr++ = ( size.GetHeight() >> 8u ) & 0xff; // Bit-pack the FittingMode, SamplingMode and atlasing. - // FittingMode=2bits, SamplingMode=3bits, useAtlas=1bit, storageType=2bits - *hashTargetPtr = ( fittingMode << 6u ) | ( samplingMode << 3 ) | ( useAtlas << 2 ) | static_cast(storageType); + // FittingMode=2bits, SamplingMode=3bits, useAtlas=1bit + *hashTargetPtr = ( fittingMode << 4u ) | ( samplingMode << 1 ) | useAtlas; } else { @@ -1257,7 +1262,6 @@ int TextureManager::FindCachedTexture( const bool useAtlas, TextureId maskTextureId, TextureManager::MultiplyOnLoad preMultiplyOnLoad, - StorageType storageType, bool isAnimatedImage, uint32_t frameIndex ) { @@ -1280,7 +1284,6 @@ int TextureManager::FindCachedTexture( ( ( size.GetWidth() == 0 && size.GetHeight() == 0 ) || ( fittingMode == textureInfo.fittingMode && samplingMode == textureInfo.samplingMode ) ) && - ( storageType == textureInfo.storageType ) && ( isAnimatedImage == ( ( textureInfo.animatedImageLoading ) ? true : false ) ) && ( frameIndex == textureInfo.frameIndex ) ) { @@ -1399,6 +1402,11 @@ void TextureManager::SetBrokenImageUrl(const std::string& brokenImageUrl) mBrokenImageUrl = brokenImageUrl; } +const std::string TextureManager::GetBrokenImageUrl() +{ + return mBrokenImageUrl; +} + Geometry TextureManager::GetRenderGeometry(TextureId textureId, uint32_t& frontElements, uint32_t& backElements ) { return RenderingAddOn::Get().IsValid() ? diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.h b/dali-toolkit/internal/visuals/texture-manager-impl.h index 89afd47..a3da3fc 100644 --- a/dali-toolkit/internal/visuals/texture-manager-impl.h +++ b/dali-toolkit/internal/visuals/texture-manager-impl.h @@ -428,6 +428,12 @@ public: void SetBrokenImageUrl(const std::string& brokenImageUrl); /** + * @brief Get an image to be used when a visual has failed to correctly render + * @return Returns The broken image url. + */ + const std::string GetBrokenImageUrl(); + + /** * @brief Returns the geometry associated with texture. * @param[in] textureId Id of the texture * @param[out] frontElements number of front elements @@ -753,7 +759,7 @@ private: TextureHash GenerateHash( const std::string& url, const ImageDimensions size, const FittingMode::Type fittingMode, const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas, - TextureId maskTextureId, StorageType storageType, bool isAnimatedImage, uint32_t frameIndex ); + TextureId maskTextureId, bool isAnimatedImage, uint32_t frameIndex ); /** * @brief Looks up a cached texture by its hash. @@ -766,7 +772,6 @@ private: * @param[in] useAtlas True if atlased * @param[in] maskTextureId Optional texture ID to use to mask this image * @param[in] preMultiplyOnLoad if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha. - * @param[in] storageType Whether the pixel data is stored in the cache, returned with PixelBuffer or uploaded to the GPU * @param[in] isAnimatedImage The boolean value to know whether the request is for animated image or not * @param[in] frameIndex The frame index of a frame to be loaded frame * @return A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found. @@ -780,7 +785,6 @@ private: const bool useAtlas, TextureId maskTextureId, MultiplyOnLoad preMultiplyOnLoad, - StorageType storageType, bool isAnimatedImage, uint32_t frameIndex ); diff --git a/dali-toolkit/public-api/dali-toolkit-version.cpp b/dali-toolkit/public-api/dali-toolkit-version.cpp index 8f76009..9fa27ae 100644 --- a/dali-toolkit/public-api/dali-toolkit-version.cpp +++ b/dali-toolkit/public-api/dali-toolkit-version.cpp @@ -29,7 +29,7 @@ namespace Toolkit { const unsigned int TOOLKIT_MAJOR_VERSION = 2; const unsigned int TOOLKIT_MINOR_VERSION = 0; -const unsigned int TOOLKIT_MICRO_VERSION = 2; +const unsigned int TOOLKIT_MICRO_VERSION = 3; const char* const TOOLKIT_BUILD_DATE = __DATE__ " " __TIME__; #ifdef DEBUG_ENABLED diff --git a/packaging/dali-toolkit.spec b/packaging/dali-toolkit.spec index 45a81e7..fd08b0b 100644 --- a/packaging/dali-toolkit.spec +++ b/packaging/dali-toolkit.spec @@ -1,6 +1,6 @@ Name: dali2-toolkit Summary: Dali 3D engine Toolkit -Version: 2.0.2 +Version: 2.0.3 Release: 1 Group: System/Libraries License: Apache-2.0 and BSD-3-Clause and MIT