namespace Internal
{
-typedef IntrusivePtr<VisualFactoryCache> VisualFactoryCachePtr;
-
DummyVisualPtr DummyVisual::New( const Property::Map& properties )
{
- VisualFactoryCachePtr factoryCache = new VisualFactoryCache;
+ VisualFactoryCache* factoryCache = new VisualFactoryCache(false);
- DummyVisualPtr dummyVisualPtr( new DummyVisual( *( factoryCache.Get() ) ) );
+ DummyVisualPtr dummyVisualPtr( new DummyVisual( *factoryCache ) );
return dummyVisualPtr;
}
#include <dali-toolkit/internal/text/rendering/text-typesetter.h>
#include <dali-toolkit/internal/text/rendering/view-model.h>
#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
using namespace Dali;
using namespace Toolkit;
DALI_TEST_CHECK( renderingController );
// Renders the text and creates the final bitmap.
- PixelData bitmap = renderingController->Render( relayoutSize );
+ PixelData bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
DALI_TEST_CHECK( bitmap );
DALI_TEST_EQUALS( 120u, bitmap.GetWidth(), TEST_LOCATION );
controller->Relayout( relayoutSize );
// Renders the text and creates the final bitmap.
- bitmap = renderingController->Render( relayoutSize );
+ bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
DALI_TEST_CHECK( bitmap );
DALI_TEST_EQUALS( 120u, bitmap.GetWidth(), TEST_LOCATION );
controller->Relayout( relayoutSize );
// Renders the text and creates the final bitmap.
- bitmap = renderingController->Render( relayoutSize );
+ bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
DALI_TEST_CHECK( bitmap );
DALI_TEST_EQUALS( 120u, bitmap.GetWidth(), TEST_LOCATION );
DALI_TEST_CHECK( renderingController );
{
- controller->SetVerticalLineAlignment(Dali::Toolkit::DevelText::VerticalLineAlignment::TOP);
- controller->Relayout(relayoutSize);
+ controller->SetVerticalLineAlignment( Dali::Toolkit::DevelText::VerticalLineAlignment::TOP );
+ controller->Relayout( relayoutSize );
// Renders the text and creates the final bitmap.
- auto bitmap = renderingController->Render(relayoutSize);
+ auto bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
DALI_TEST_EQUALS( 60u, bitmap.GetHeight(), TEST_LOCATION );
}
{
- controller->SetVerticalLineAlignment(Dali::Toolkit::DevelText::VerticalLineAlignment::MIDDLE);
- controller->Relayout(relayoutSize);
+ controller->SetVerticalLineAlignment( Dali::Toolkit::DevelText::VerticalLineAlignment::MIDDLE );
+ controller->Relayout( relayoutSize );
// Renders the text and creates the final bitmap.
- auto bitmap = renderingController->Render(relayoutSize);
+ auto bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
DALI_TEST_EQUALS( 60u, bitmap.GetHeight(), TEST_LOCATION );
}
{
- controller->SetVerticalLineAlignment(Dali::Toolkit::DevelText::VerticalLineAlignment::BOTTOM);
- controller->Relayout(relayoutSize);
+ controller->SetVerticalLineAlignment( Dali::Toolkit::DevelText::VerticalLineAlignment::BOTTOM );
+ controller->Relayout( relayoutSize );
// Renders the text and creates the final bitmap.
- auto bitmap = renderingController->Render(relayoutSize);
+ auto bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
DALI_TEST_EQUALS( 60u, bitmap.GetHeight(), TEST_LOCATION );
}
tet_result(TET_PASS);
END_TEST;
-}
\ No newline at end of file
+}
{
}
- void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect )
+ virtual void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet,
+ bool useAtlasing, const Vector4& atlasRect, bool preMultiplied ) override
{
mLoaded = loadSuccess;
mObserverCalled = true;
TestObserver observer;
std::string filename("image.png");
-
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
TextureManager::TextureId textureId = textureManager.RequestLoad(
filename,
ImageDimensions(),
TextureManager::NO_ATLAS,
&observer,
true,
- TextureManager::ReloadPolicy::CACHED );
+ TextureManager::ReloadPolicy::CACHED,
+ preMultiply);
const VisualUrl& url = textureManager.GetVisualUrl( textureId );
const char* TEST_LARGE_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/tbcol.png";
const char* TEST_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+Vector4 GetControlBackgroundColor( Control& control )
+{
+ Property::Value propValue = control.GetProperty( Control::Property::BACKGROUND );
+ Property::Map* resultMap = propValue.GetMap();
+ DALI_TEST_CHECK( resultMap->Find( ColorVisual::Property::MIX_COLOR ) );
+
+ Vector4 color;
+ resultMap->Find( ColorVisual::Property::MIX_COLOR )->Get( color );
+
+ return color;
+}
+
} // namespace
///////////////////////////////////////////////////////////////////////////////////////////////////
END_TEST;
}
+int UtcDaliControlBackgroundColorRendererCount(void)
+{
+ tet_infoline( "Test ensures we only create renderers when non-transparent color is requested or if we our clipping-mode is set to CLIP_CHILDREN" );
+
+ ToolkitTestApplication application;
+ Control control = Control::New();
+ Stage::GetCurrent().Add( control );
+
+ tet_infoline( "Set transparent, no renderers should be created" );
+ control.SetBackgroundColor( Color::TRANSPARENT );
+ application.SendNotification();
+ application.Render();
+ DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+
+ tet_infoline( "Set transparent alpha with positive RGB values, no renderers should be created, but returned color should reflect what we set" );
+ const Vector4 alphaZero( 1.0f, 0.5f, 0.25f, 0.0f );
+ control.SetBackgroundColor( alphaZero );
+ application.SendNotification();
+ application.Render();
+ DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetControlBackgroundColor( control ), alphaZero, TEST_LOCATION );
+
+ tet_infoline( "Set semi transparent alpha with positive RGB values, 1 renderer should be created, but returned color should reflect what we set" );
+ const Vector4 semiTransparent( 1.0f, 0.75f, 0.5f, 0.5f );
+ control.SetBackgroundColor( semiTransparent );
+ application.SendNotification();
+ application.Render();
+ DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetControlBackgroundColor( control ), semiTransparent, TEST_LOCATION );
+
+ tet_infoline( "Set transparent, ensure no renderers are created" );
+ control.SetBackgroundColor( Color::TRANSPARENT );
+ application.SendNotification();
+ application.Render();
+ DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
+
+ tet_infoline( "Set control to clip its children, a renderer should be created which will be transparent" );
+ control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
+ application.SendNotification();
+ application.Render();
+ DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
+
+ tet_infoline( "Set a color, only 1 renderer should exist" );
+ control.SetBackgroundColor( Color::RED );
+ application.SendNotification();
+ application.Render();
+ DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::RED, TEST_LOCATION );
+
+ tet_infoline( "Clear the background, no renderers" );
+ control.ClearBackground();
+ application.SendNotification();
+ application.Render();
+ DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+
+ tet_infoline( "Set control to clip its children again, a renderer should be created which will be transparent" );
+ control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
+ application.SendNotification();
+ application.Render();
+ DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
+
+ tet_infoline( "Disable clipping, no renderers" );
+ control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::DISABLED );
+ application.SendNotification();
+ application.Render();
+ DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+ DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
+
+ END_TEST;
+}
+
int UtcDaliControlBackgroundImage(void)
{
ToolkitTestApplication application;
VisualFactory factory = VisualFactory::Get();
DALI_TEST_CHECK( factory );
+ factory.SetPreMultiplyOnLoad( true );
Property::Map propertyMap;
propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::IMAGE );
DummyControl actor = DummyControl::New();
DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+ actor.SetSize( 200.f, 200.f );
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+ Stage::GetCurrent().Add( actor );
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+ auto renderer = actor.GetRendererAt(0);
+ auto preMultipliedIndex = renderer.GetPropertyIndex( "preMultipliedAlpha" );
+ DALI_TEST_CHECK( preMultipliedIndex != Property::INVALID_INDEX );
+ auto preMultipliedAlpha = renderer.GetProperty<float>( preMultipliedIndex );
+ auto preMultipliedAlpha2 = renderer.GetProperty<bool>( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+ DALI_TEST_EQUALS( preMultipliedAlpha, 1.0f, TEST_LOCATION );
+ DALI_TEST_EQUALS( preMultipliedAlpha2, true, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+ Stage::GetCurrent().Remove( actor );
+ DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+ END_TEST;
+}
+
+
+int UtcDaliImageVisualNoPremultipliedAlpha01(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "Request image visual without pre-multiplied alpha" );
+
+ VisualFactory factory = VisualFactory::Get();
+ DALI_TEST_CHECK( factory );
+ factory.SetPreMultiplyOnLoad( false );
+
+ Property::Map propertyMap;
+ propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::IMAGE );
+ propertyMap.Insert( ImageVisual::Property::URL, TEST_LARGE_IMAGE_FILE_NAME );
+
+ Visual::Base visual = factory.CreateVisual( propertyMap );
+ DALI_TEST_CHECK( visual );
+
+ // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+ // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ DummyControl actor = DummyControl::New();
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+ dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+ actor.SetSize( 200.f, 200.f );
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+ Stage::GetCurrent().Add( actor );
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+ auto renderer = actor.GetRendererAt(0);
+ auto preMultipliedIndex = renderer.GetPropertyIndex( "preMultipliedAlpha" );
+ DALI_TEST_CHECK( preMultipliedIndex != Property::INVALID_INDEX );
+ auto preMultipliedAlpha = renderer.GetProperty<bool>( preMultipliedIndex );
+ auto preMultipliedAlpha2 = renderer.GetProperty<bool>( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+
+ DALI_TEST_EQUALS( preMultipliedAlpha, false, TEST_LOCATION );
+ DALI_TEST_EQUALS( preMultipliedAlpha2, false, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+ Stage::GetCurrent().Remove( actor );
+ DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+ END_TEST;
+}
+
+
+int UtcDaliImageVisualNoPremultipliedAlpha02(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "Request image visual with no alpha channel" );
+
+ VisualFactory factory = VisualFactory::Get();
+ DALI_TEST_CHECK( factory );
+
+ Property::Map propertyMap;
+ propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::IMAGE );
+ propertyMap.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME );
+
+ Visual::Base visual = factory.CreateVisual( propertyMap );
+ DALI_TEST_CHECK( visual );
+
+ // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+ // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ TraceCallStack& textureTrace = gl.GetTextureTrace();
+ textureTrace.Enable(true);
+
+ DummyControl actor = DummyControl::New();
+ DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
actor.SetSize( 200.f, 200.f );
application.Render();
DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+ auto renderer = actor.GetRendererAt(0);
+ auto preMultipliedIndex = renderer.GetPropertyIndex( "preMultipliedAlpha" );
+ DALI_TEST_CHECK( preMultipliedIndex != Property::INVALID_INDEX );
+ auto preMultipliedAlpha = renderer.GetProperty<bool>( preMultipliedIndex );
+ auto preMultipliedAlpha2 = renderer.GetProperty<bool>( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+
+ DALI_TEST_EQUALS( preMultipliedAlpha, false, TEST_LOCATION );
+ DALI_TEST_EQUALS( preMultipliedAlpha2, false, TEST_LOCATION );
DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
#include <dali/integration-api/events/touch-event-integ.h>
#include <dali/integration-api/events/pan-gesture-event.h>
#include <dali/integration-api/events/long-press-gesture-event.h>
+#include <dali/devel-api/adaptor-framework/key-devel.h>
#include <dali-toolkit-test-suite-utils.h>
#include <dali-toolkit/dali-toolkit.h>
#include <dali-toolkit/devel-api/controls/text-controls/text-field-devel.h>
application.SendNotification();
application.Render();
+ // Pressing delete key should be fine even if there is no text in TextField.
+ application.ProcessEvent( GenerateKey( "Delete", "Delete", Dali::DevelKey::DALI_KEY_DELETE, 0, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+ // Render and notify
+ application.SendNotification();
+ application.Render();
+
// Now the text field has the focus, so it can handle the key events.
application.ProcessEvent( GenerateKey( "a", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
application.ProcessEvent( GenerateKey( "a", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
label.SetProperty( TextLabel::Property::POINT_SIZE, 20 );
Stage::GetCurrent().Add( label );
+ // Test LTR text
DALI_TEST_EQUALS( label.GetProperty< int >( DevelTextLabel::Property::TEXT_DIRECTION ), static_cast< int >( Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT ), TEST_LOCATION );
+ // Test RTL text
label.SetProperty( TextLabel::Property::TEXT, "ﻡﺮﺤﺑﺍ ﺏﺎﻠﻋﺎﻠﻣ ﻡﺮﺤﺑﺍ" );
DALI_TEST_EQUALS( label.GetProperty< int >( DevelTextLabel::Property::TEXT_DIRECTION ), static_cast< int >( Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT ), TEST_LOCATION );
+ // Test RTL text starting with weak character
+ label.SetProperty( TextLabel::Property::TEXT, "()ﻡﺮﺤﺑﺍ ﺏﺎﻠﻋﺎﻠﻣ ﻡﺮﺤﺑﺍ" );
+ DALI_TEST_EQUALS( label.GetProperty< int >( DevelTextLabel::Property::TEXT_DIRECTION ), static_cast< int >( Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT ), TEST_LOCATION );
+
+ // Test RTL text string with emoji and weak character
+ label.SetProperty( TextLabel::Property::TEXT, "\xF0\x9F\x98\x81 () ﻡﺮﺤﺑﺍ ﺏﺎﻠﻋﺎﻠﻣ ﻡﺮﺤﺑﺍ" );
+ DALI_TEST_EQUALS( label.GetProperty< int >( DevelTextLabel::Property::TEXT_DIRECTION ), static_cast< int >( Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT ), TEST_LOCATION );
+
END_TEST;
}
#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
#include <dali-toolkit/devel-api/visual-factory/transition-data.h>
+#include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
#include <dali-toolkit/devel-api/visuals/text-visual-properties-devel.h>
END_TEST;
}
+
+int UtcDaliColorVisualRenderIfTransparentProperty(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "Test the renderIfTransparent property of ColorVisual" );
+
+ VisualFactory factory = VisualFactory::Get();
+ Property::Map propertyMap;
+ propertyMap.Insert( Visual::Property::TYPE, Visual::COLOR );
+ propertyMap.Insert( ColorVisual::Property::MIX_COLOR, Color::BLUE );
+
+ tet_infoline( "Check default value" );
+ {
+ Visual::Base testVisual = factory.CreateVisual( propertyMap );
+ Property::Map returnedMap;
+ testVisual.CreatePropertyMap( returnedMap );
+
+ Property::Value* renderIfTransparentProperty = returnedMap.Find( DevelColorVisual::Property::RENDER_IF_TRANSPARENT );
+ DALI_TEST_CHECK( renderIfTransparentProperty );
+ DALI_TEST_EQUALS( renderIfTransparentProperty->Get< bool >(), false, TEST_LOCATION );
+ }
+
+ propertyMap.Insert( DevelColorVisual::Property::RENDER_IF_TRANSPARENT, true );
+
+ tet_infoline( "Ensure set to value required" );
+ {
+ Visual::Base testVisual = factory.CreateVisual( propertyMap );
+ Property::Map returnedMap;
+ testVisual.CreatePropertyMap( returnedMap );
+
+ Property::Value* renderIfTransparentProperty = returnedMap.Find( DevelColorVisual::Property::RENDER_IF_TRANSPARENT );
+ DALI_TEST_CHECK( renderIfTransparentProperty );
+ DALI_TEST_EQUALS( renderIfTransparentProperty->Get< bool >(), true, TEST_LOCATION );
+ }
+
+ propertyMap[ DevelColorVisual::Property::RENDER_IF_TRANSPARENT ] = Color::BLUE;
+
+ tet_infoline( "Ensure it returns default value if set to wrong type" );
+ {
+ Visual::Base testVisual = factory.CreateVisual( propertyMap );
+ Property::Map returnedMap;
+ testVisual.CreatePropertyMap( returnedMap );
+
+ Property::Value* renderIfTransparentProperty = returnedMap.Find( DevelColorVisual::Property::RENDER_IF_TRANSPARENT );
+ DALI_TEST_CHECK( renderIfTransparentProperty );
+ DALI_TEST_EQUALS( renderIfTransparentProperty->Get< bool >(), false, TEST_LOCATION );
+ }
+
+ END_TEST;
+}
ToolkitTestApplication application;
tet_infoline( "UtcDaliVisualFactoryGetAnimatedImageVisual1: Request animated image visual with a gif url" );
- VisualFactory factory = VisualFactory::Get();
- Visual::Base visual = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() );
- DALI_TEST_CHECK( visual );
-
TestGlAbstraction& gl = application.GetGlAbstraction();
TraceCallStack& textureTrace = gl.GetTextureTrace();
textureTrace.Enable(true);
+ VisualFactory factory = VisualFactory::Get();
+ Visual::Base visual = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() );
+ DALI_TEST_CHECK( visual );
+
DummyControl actor = DummyControl::New(true);
DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
// renderer is added to actor
DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
-
- // test the uniforms which used to handle the atlas rect
- // the four frames should be located inside atlas as follows: atlas size 100*100
- // -------------
- // | | |
- // | 0 | 1 |
- // -------------
- // | | |
- // | 2 | 3 |
- // -------------
-
Renderer renderer = actor.GetRendererAt( 0u );
DALI_TEST_CHECK( renderer );
- Property::Value atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) );
- // take into consideration the half pixel correction
- DALI_TEST_EQUALS( atlasRectValue.Get<Vector4>(), Vector4(0.5f, 0.5f, 49.5f, 49.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
-
- // waiting for the resource uploading
- application.SendNotification();
- application.Render();
-
- DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+ textureTrace.Reset();
// Force the timer used by the animatedImageVisual to tick,
Dali::Timer timer = Timer::New( 0 );
timer.MockEmitSignal();
application.SendNotification();
application.Render();
- atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) );
- // take into consideration the half pixel correction
- DALI_TEST_EQUALS( atlasRectValue.Get<Vector4>(), Vector4(50.5f, 0.5f, 99.5f, 49.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+ textureTrace.Reset();
+
// Force the timer used by the animatedImageVisual to tick,
timer.MockEmitSignal();
application.SendNotification();
application.Render();
- atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) );
- // take into consideration the half pixel correction
- DALI_TEST_EQUALS( atlasRectValue.Get<Vector4>(), Vector4(0.5f, 50.5f, 49.5f, 99.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+ textureTrace.Reset();
// Force the timer used by the animatedImageVisual to tick,
timer.MockEmitSignal();
application.SendNotification();
application.Render();
- atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) );
- // take into consideration the half pixel correction
- DALI_TEST_EQUALS( atlasRectValue.Get<Vector4>(), Vector4(50.5f, 50.5f, 99.5f, 99.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+ textureTrace.Reset();
// Test SetOffStage().
actor.Unparent();
$(devel_api_src_dir)/visual-factory/visual-base.h
devel_api_visuals_header_files = \
+ $(devel_api_src_dir)/visuals/animated-gradient-visual-properties-devel.h \
+ $(devel_api_src_dir)/visuals/color-visual-properties-devel.h \
$(devel_api_src_dir)/visuals/image-visual-properties-devel.h \
$(devel_api_src_dir)/visuals/image-visual-actions-devel.h \
- $(devel_api_src_dir)/visuals/animated-gradient-visual-properties-devel.h \
$(devel_api_src_dir)/visuals/text-visual-properties-devel.h \
$(devel_api_src_dir)/visuals/visual-properties-devel.h
return GetImplementation( *this ).CreateVisual( url, size );
}
+void VisualFactory::SetPreMultiplyOnLoad( bool preMultiply )
+{
+ GetImplementation( *this ).SetPreMultiplyOnLoad( preMultiply );
+}
+
+bool VisualFactory::GetPreMultiplyOnLoad() const
+{
+ return GetImplementation( *this ).GetPreMultiplyOnLoad();
+}
+
} // namespace Toolkit
} // namespace Dali
*/
Visual::Base CreateVisual( const std::string& url, ImageDimensions size );
+ /**
+ * @brief Enable or disable premultiplying alpha in images and image visuals.
+ *
+ * The default is to enable pre-multiplication on load.
+ *
+ * Applications that have assets with pre-multiplied alpha already applied should turn this option off.
+ *
+ * @param[in] preMultiply True if loaded images for image visuals should have alpha multiplied into the color
+ * channels.
+ */
+ void SetPreMultiplyOnLoad( bool preMultiply );
+
+ /**
+ * @brief Get the setting for automatically pre-multiplying image visual images on load.
+ *
+ * @return True if loaded images have pre-multiplied alpha applied on load, false otherwise.
+ */
+ bool GetPreMultiplyOnLoad() const;
+
private:
explicit DALI_INTERNAL VisualFactory(Internal::VisualFactory *impl);
--- /dev/null
+#ifndef DALI_TOOLKIT_COLOR_VISUAL_PROPERTIES_DEVEL_H
+#define DALI_TOOLKIT_COLOR_VISUAL_PROPERTIES_DEVEL_H
+
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+
+namespace DevelColorVisual
+{
+
+/**
+ * @brief Additional ColorVisual Properties.
+ */
+namespace Property
+{
+
+/**
+ * @brief Enumeration for the instance of additional properties belonging to the ColorVisual.
+ */
+enum
+{
+ MIX_COLOR = Toolkit::ColorVisual::Property::MIX_COLOR,
+
+ /**
+ * @brief Whether to render if the MIX_COLOR is transparent.
+ * @details Name "renderIfTransparent", type Property::BOOLEAN.
+ * @note Optional.
+ * @note By default it's false, i.e. ColorVisual will not render if the MIX_COLOR is transparent.
+ */
+ RENDER_IF_TRANSPARENT = MIX_COLOR + 1,
+};
+
+} // namespace Property
+
+} // namespace ColorVisual
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_COLOR_VISUAL_PROPERTIES_DEVEL_H
namespace
{
const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
+
+ /**
+ * @brief How the text visual should be aligned vertically inside the control.
+ *
+ * 0.0f aligns the text to the top, 0.5f aligns the text to the center, 1.0f aligns the text to the bottom.
+ * The alignment depends on the alignment value of the text label (Use Text::VerticalAlignment enumerations).
+ */
+ const float VERTICAL_ALIGNMENT_TABLE[ Text::VerticalAlignment::BOTTOM + 1 ] =
+ {
+ 0.0f, // VerticalAlignment::TOP
+ 0.5f, // VerticalAlignment::CENTER
+ 1.0f // VerticalAlignment::BOTTOM
+ };
}
namespace
std::swap( padding.start, padding.end );
}
+ // Calculate the size of the visual that can fit the text
+ Size layoutSize = mController->GetTextModel()->GetLayoutSize();
+ layoutSize.x = contentSize.x;
+
+ const Vector2& shadowOffset = mController->GetTextModel()->GetShadowOffset();
+ if ( shadowOffset.y > Math::MACHINE_EPSILON_1 )
+ {
+ layoutSize.y += shadowOffset.y;
+ }
+
+ float outlineWidth = mController->GetTextModel()->GetOutlineWidth();
+ layoutSize.y += outlineWidth * 2.0f;
+ layoutSize.y = std::min( layoutSize.y, contentSize.y );
+
+ // Calculate the offset for vertical alignment only, as the layout engine will do the horizontal alignment.
+ Vector2 alignmentOffset;
+ alignmentOffset.x = 0.0f;
+ alignmentOffset.y = ( contentSize.y - layoutSize.y ) * VERTICAL_ALIGNMENT_TABLE[mController->GetVerticalAlignment()];
+
Property::Map visualTransform;
- visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, contentSize )
+ visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, layoutSize )
.Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
- .Add( Toolkit::Visual::Transform::Property::OFFSET, Vector2( padding.start, padding.top ) )
+ .Add( Toolkit::Visual::Transform::Property::OFFSET, Vector2( padding.start, padding.top ) + alignmentOffset )
.Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
.Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
.Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN );
Text::TypesetterPtr typesetter = Text::Typesetter::New( mController->GetTextModel() );
- PixelData data = typesetter->Render( verifiedSize, Text::Typesetter::RENDER_TEXT_AND_STYLES, true, Pixel::RGBA8888 ); // ignore the horizontal alignment
+ PixelData data = typesetter->Render( verifiedSize, mController->GetTextDirection(), Text::Typesetter::RENDER_TEXT_AND_STYLES, true, Pixel::RGBA8888 ); // ignore the horizontal alignment
Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
data.GetPixelFormat(),
data.GetWidth(),
$(toolkit_src_dir)/visuals/animated-image/image-cache.cpp \
$(toolkit_src_dir)/visuals/animated-image/fixed-image-cache.cpp \
$(toolkit_src_dir)/visuals/animated-image/rolling-image-cache.cpp \
+ $(toolkit_src_dir)/visuals/animated-image/rolling-gif-image-cache.cpp \
$(toolkit_src_dir)/visuals/border/border-visual.cpp \
$(toolkit_src_dir)/visuals/color/color-visual.cpp \
$(toolkit_src_dir)/visuals/gradient/gradient-visual.cpp \
void GetCursorPosition( GetCursorPositionParameters& parameters,
CursorInfo& cursorInfo )
{
+ const LineRun* const modelLines = parameters.visualModel->mLines.Begin();
+ if( NULL == modelLines )
+ {
+ // Nothing to do.
+ return;
+ }
+
// Whether the logical cursor position is at the end of the whole text.
const bool isLastPosition = parameters.logicalModel->mText.Count() == parameters.logical;
// Whether the cursor is in the last position and the last position is a new paragraph character.
const bool isLastNewParagraph = parameters.isMultiline && isLastPosition && TextAbstraction::IsNewParagraph( *( parameters.logicalModel->mText.Begin() + characterOfLine ) );
- const LineRun* const modelLines = parameters.visualModel->mLines.Begin();
-
const LineIndex lineIndex = parameters.visualModel->GetLineOfCharacter( characterOfLine );
const LineRun& line = *( modelLines + lineIndex );
// Set the primary cursor's height.
cursorInfo.primaryCursorHeight = cursorInfo.isSecondaryCursor ? 0.5f * glyphMetrics.fontHeight : glyphMetrics.fontHeight;
-
cursorInfo.glyphOffset = line.ascender - glyphMetrics.ascender;
// Set the primary cursor's position.
cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + primaryPosition.x + glyphAdvance;
return mModel;
}
-PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat )
+PixelData Typesetter::Render( const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat )
{
// @todo. This initial implementation for a TextLabel has only one visible page.
// Retrieves the layout size.
const Size& layoutSize = mModel->GetLayoutSize();
+ const float outlineWidth = mModel->GetOutlineWidth();
+
+ // Set the offset for the horizontal alignment according to the text direction and outline width.
+ int penX = 0;
+
+ switch( mModel->GetHorizontalAlignment() )
+ {
+ case HorizontalAlignment::BEGIN:
+ {
+ // No offset to add.
+ break;
+ }
+ case HorizontalAlignment::CENTER:
+ {
+ penX += ( textDirection == Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT ) ? -outlineWidth : outlineWidth;
+ break;
+ }
+ case HorizontalAlignment::END:
+ {
+ penX += ( textDirection == Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT ) ? -outlineWidth * 2.0f : outlineWidth * 2.0f;
+ break;
+ }
+ }
+
// Set the offset for the vertical alignment.
- int penY = 0u;
+ int penY = 0;
switch( mModel->GetVerticalAlignment() )
{
if( RENDER_MASK == behaviour )
{
// Generate the image buffer as an alpha mask for color glyphs.
- imageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_MASK, ignoreHorizontalAlignment, pixelFormat, penY, 0u, numberOfGlyphs - 1 );
+ imageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_MASK, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs - 1 );
}
else if( RENDER_NO_TEXT == behaviour )
{
else
{
// Generate the image buffer for the text with no style.
- imageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_NONE, ignoreHorizontalAlignment, pixelFormat, penY, 0u, numberOfGlyphs -1 );
+ imageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_NONE, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs -1 );
}
if ( ( RENDER_NO_STYLES != behaviour ) && ( RENDER_MASK != behaviour ) )
if ( outlineWidth > Math::MACHINE_EPSILON_1 )
{
// Create the image buffer for outline
- Devel::PixelBuffer outlineImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_OUTLINE, ignoreHorizontalAlignment, pixelFormat, penY, 0u, numberOfGlyphs -1 );
+ Devel::PixelBuffer outlineImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_OUTLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs -1 );
// Combine the two buffers
imageBuffer = CombineImageBuffer( imageBuffer, outlineImageBuffer, bufferWidth, bufferHeight );
if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 )
{
// Create the image buffer for shadow
- Devel::PixelBuffer shadowImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_SHADOW, ignoreHorizontalAlignment, pixelFormat, penY, 0u, numberOfGlyphs - 1 );
+ Devel::PixelBuffer shadowImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_SHADOW, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs - 1 );
// Check whether it will be a soft shadow
const float& blurRadius = mModel->GetShadowBlurRadius();
if ( underlineEnabled )
{
// Create the image buffer for underline
- Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, penY, 0u, numberOfGlyphs - 1 );
+ Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs - 1 );
// Combine the two buffers
imageBuffer = CombineImageBuffer( imageBuffer, underlineImageBuffer, bufferWidth, bufferHeight );
return pixelData;
}
-Devel::PixelBuffer Typesetter::CreateImageBuffer( const unsigned int bufferWidth, const unsigned int bufferHeight, Typesetter::Style style, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int verticalOffset, GlyphIndex fromGlyphIndex, GlyphIndex toGlyphIndex )
+Devel::PixelBuffer Typesetter::CreateImageBuffer( const unsigned int bufferWidth, const unsigned int bufferHeight, Typesetter::Style style, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int horizontalOffset, int verticalOffset, GlyphIndex fromGlyphIndex, GlyphIndex toGlyphIndex )
{
// Retrieve lines, glyphs, positions and colors from the view model.
const Length modelNumberOfLines = mModel->GetNumberOfLines();
// Sets the horizontal offset of the line.
glyphData.horizontalOffset = ignoreHorizontalAlignment ? 0 : static_cast<int>( line.alignmentOffset );
+ glyphData.horizontalOffset += horizontalOffset;
// Increases the vertical offset with the line's ascender.
glyphData.verticalOffset += static_cast<int>( line.ascender );
#include <dali/public-api/images/pixel-data.h>
#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
namespace Dali
{
* - Combines different image buffers to create the pixel data used to generate the final image
*
* @param[in] size The renderer size.
+ * @param[in] textDirection The direction of the text.
* @param[in] behaviour The behaviour of how to render the text (i.e. whether to render the text only or the styles only or both).
* @param[in] ignoreHorizontalAlignment Whether to ignore the horizontal alignment (i.e. always render as if HORIZONTAL_ALIGN_BEGIN).
* @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
*
* @return A pixel data with the text rendered.
*/
- PixelData Render( const Vector2& size, RenderBehaviour behaviour = RENDER_TEXT_AND_STYLES, bool ignoreHorizontalAlignment = false, Pixel::Format pixelFormat = Pixel::RGBA8888 );
+ PixelData Render( const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour = RENDER_TEXT_AND_STYLES, bool ignoreHorizontalAlignment = false, Pixel::Format pixelFormat = Pixel::RGBA8888 );
private:
/**
* @param[in] style The style of the text.
* @param[in] ignoreHorizontalAlignment Whether to ignore the horizontal alignment, not ignored by default.
* @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
+ * @param[in] horizontalOffset The horizontal offset to be added to the glyph's position.
* @param[in] verticalOffset The vertical offset to be added to the glyph's position.
* @param[in] fromGlyphIndex The index of the first glyph within the text to be drawn
* @param[in] toGlyphIndex The index of the last glyph within the text to be drawn
*
* @return An image buffer with the text.
*/
- Devel::PixelBuffer CreateImageBuffer( const unsigned int bufferWidth, const unsigned int bufferHeight, Typesetter::Style style, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int verticalOffset, TextAbstraction::GlyphIndex fromGlyphIndex, TextAbstraction::GlyphIndex toGlyphIndex );
+ Devel::PixelBuffer CreateImageBuffer( const unsigned int bufferWidth, const unsigned int bufferHeight, Typesetter::Style style, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int horizontalOffset, int verticalOffset, TextAbstraction::GlyphIndex fromGlyphIndex, TextAbstraction::GlyphIndex toGlyphIndex );
/**
* @brief Combine the two RGBA image buffers together.
mMarkupProcessorEnabled( false ),
mClipboardHideEnabled( true ),
mIsAutoScrollEnabled( false ),
- mAutoScrollDirectionRTL( false ),
+ mUpdateTextDirection( true ),
+ mIsTextDirectionRTL( false ),
mUnderlineSetByString( false ),
mShadowSetByString( false ),
mOutlineSetByString( false ),
bool mMarkupProcessorEnabled:1; ///< Whether the mark-up procesor is enabled.
bool mClipboardHideEnabled:1; ///< Whether the ClipboardHide function work or not
bool mIsAutoScrollEnabled:1; ///< Whether auto text scrolling is enabled.
- CharacterDirection mAutoScrollDirectionRTL:1; ///< Direction of auto scrolling, true if rtl
+ bool mUpdateTextDirection:1; ///< Whether the text direction needs to be updated.
+ CharacterDirection mIsTextDirectionRTL:1; ///< Whether the text direction is right to left or not
bool mUnderlineSetByString:1; ///< Set when underline is set by string (legacy) instead of map
bool mShadowSetByString:1; ///< Set when shadow is set by string (legacy) instead of map
CharacterDirection Controller::GetAutoScrollDirection() const
{
- return mImpl->mAutoScrollDirectionRTL;
+ return mImpl->mIsTextDirectionRTL;
}
float Controller::GetAutoScrollLineAlignment() const
// The natural size needs to be re-calculated.
mImpl->mRecalculateNaturalSize = true;
+ // The text direction needs to be updated.
+ mImpl->mUpdateTextDirection = true;
+
// Apply modifications to the model
mImpl->mOperationsPending = ALL_OPERATIONS;
}
Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
{
- if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
+ // Make sure the model is up-to-date before layouting
+ ProcessModifyEvents();
+
+ if ( mImpl->mUpdateTextDirection )
{
- return Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
- }
+ // Operations that can be done only once until the text changes.
+ const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( GET_SCRIPTS |
+ VALIDATE_FONTS |
+ GET_LINE_BREAKS |
+ GET_WORD_BREAKS |
+ BIDI_INFO |
+ SHAPE_TEXT );
- const Character character = mImpl->mModel->mLogicalModel->mText[0];
- Script script = TextAbstraction::GetCharacterScript( character );
+ // Set the update info to relayout the whole text.
+ mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+ mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
- if( TextAbstraction::IsRightToLeftScript( script ) )
- {
- return Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT;
+ // Make sure the model is up-to-date before layouting
+ mImpl->UpdateModel( onlyOnceOperations );
+
+ Vector3 naturalSize;
+ DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
+ static_cast<OperationsMask>( onlyOnceOperations |
+ LAYOUT | REORDER | UPDATE_DIRECTION ),
+ naturalSize.GetVectorXY() );
+
+ // Clear the update info. This info will be set the next time the text is updated.
+ mImpl->mTextUpdateInfo.Clear();
+
+ mImpl->mUpdateTextDirection = false;
}
- return Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
+ return mImpl->mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
}
Toolkit::DevelText::VerticalLineAlignment::Type Controller::GetVerticalLineAlignment() const
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height );
+ if( ( 0 == mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd ) &&
+ ( 0 == mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) &&
+ ( ( mImpl->mModel->mVisualModel->mControlSize.width < Math::MACHINE_EPSILON_1000 ) || ( mImpl->mModel->mVisualModel->mControlSize.height < Math::MACHINE_EPSILON_1000 ) ) )
+ {
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
+ }
+
// Layout operations that need to be done if the size changes.
mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
LAYOUT |
const float outlineWidth = static_cast<float>( mImpl->mModel->GetOutlineWidth() );
// Set the layout parameters.
- Layout::Parameters layoutParameters( size,
+ const Vector2 sizeOffset = Vector2(outlineWidth * 2.0f, outlineWidth * 2.0f); // The outline should be fit into the bounding box
+ Layout::Parameters layoutParameters( size - sizeOffset,
textBuffer,
lineBreakInfo.Begin(),
wordBreakInfo.Begin(),
if( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
{
- mImpl->mAutoScrollDirectionRTL = false;
+ mImpl->mIsTextDirectionRTL = false;
}
// Reorder the lines
const LineRun* const firstline = mImpl->mModel->mVisualModel->mLines.Begin();
if ( firstline )
{
- mImpl->mAutoScrollDirectionRTL = firstline->direction;
+ mImpl->mIsTextDirectionRTL = firstline->direction;
}
}
}
#if defined(DEBUG_ENABLED)
std::string currentText;
GetText( currentText );
- DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mAutoScrollDirectionRTL[%s] [%s]\n", this, (mImpl->mAutoScrollDirectionRTL)?"true":"false", currentText.c_str() );
+ DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mIsTextDirectionRTL[%s] [%s]\n", this, (mImpl->mIsTextDirectionRTL)?"true":"false", currentText.c_str() );
#endif
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
return viewUpdated;
// The natural size needs to be re-calculated.
mImpl->mRecalculateNaturalSize = true;
+ // The text direction needs to be updated.
+ mImpl->mUpdateTextDirection = true;
+
// Apply modifications to the model
mImpl->mOperationsPending = ALL_OPERATIONS;
}
// The natural size needs to be re-calculated.
mImpl->mRecalculateNaturalSize = true;
+ // The text direction needs to be updated.
+ mImpl->mUpdateTextDirection = true;
+
// Apply modifications to the model; TODO - Optimize this
mImpl->mOperationsPending = ALL_OPERATIONS;
}
// The natural size needs to be re-calculated.
mImpl->mRecalculateNaturalSize = true;
+ // The text direction needs to be updated.
+ mImpl->mUpdateTextDirection = true;
+
// Apply modifications to the model; TODO - Optimize this
mImpl->mOperationsPending = ALL_OPERATIONS;
}
// The natural size needs to be re-calculated.
mImpl->mRecalculateNaturalSize = true;
+ // The text direction needs to be updated.
+ mImpl->mUpdateTextDirection = true;
+
// Apply modifications to the model
mImpl->mOperationsPending = ALL_OPERATIONS;
}
// The natural size needs to be re-calculated.
mImpl->mRecalculateNaturalSize = true;
+ // The text direction needs to be updated.
+ mImpl->mUpdateTextDirection = true;
+
// Apply modifications to the model
mImpl->mOperationsPending = ALL_OPERATIONS;
mediump vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy );\n
mediump vec2 visualSize = mix( uSize.xy * size, size, offsetSizeMode.zw );\n
\n
- mediump float delta = floor ( uDelta ) + 0.5;\n
- vTexCoord.x = ( delta + uHorizontalAlign * ( uTextureSize.x - visualSize.x - uGap ) + floor( aPosition.x * visualSize.x ) + 0.5 - uGap * 0.5 ) / uTextureSize.x + 0.5;\n
+ vTexCoord.x = ( uDelta + uHorizontalAlign * ( uTextureSize.x - visualSize.x - uGap ) + floor( aPosition.x * visualSize.x ) + 0.5 - uGap * 0.5 ) / uTextureSize.x + 0.5;\n
vTexCoord.y = ( uVerticalAlign * ( uTextureSize.y - visualSize.y ) + floor( aPosition.y * visualSize.y ) + 0.5 ) / ( uTextureSize.y ) + 0.5;\n
\n
mediump vec4 vertexPosition = vec4( floor( ( aPosition + anchorPoint ) * visualSize + ( visualOffset + origin ) * uSize.xy ), 0.0, 1.0 );\n
- mediump vec4 nonAlignedVertex = uViewMatrix * uModelMatrix * vertexPosition;\n
- mediump vec4 pixelAlignedVertex = vec4 ( floor( nonAlignedVertex.xyz ), 1.0 );\n
\n
- gl_Position = uProjection * pixelAlignedVertex;\n
+ gl_Position = uProjection * uViewMatrix * uModelMatrix * vertexPosition;\n
}\n
);
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetParameters wrapGap[%f]\n", wrapGap );
- const float horizontalAlign = HORIZONTAL_ALIGNMENT_TABLE[ horizontalAlignment ][ direction ];
+ float horizontalAlign;
+
+ if( textureSize.x > controlSize.x )
+ {
+ // if Text is elided, scroll should start at the begin of text.
+ horizontalAlign = HORIZONTAL_ALIGNMENT_TABLE[HorizontalAlignment::BEGIN][ direction ];
+ }
+ else
+ {
+ horizontalAlign = HORIZONTAL_ALIGNMENT_TABLE[ horizontalAlignment ][ direction ];
+ }
+
const float verticalAlign = VERTICAL_ALIGNMENT_TABLE[ verticalAlignment ];
+
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetParameters horizontalAlign[%f], verticalAlign[%f]\n", horizontalAlign, verticalAlign );
scrollingTextActor.RegisterProperty( "uTextureSize", textureSize );
LineIndex VisualModel::GetLineOfCharacter( CharacterIndex characterIndex )
{
- // 1) Check first in the cached line.
+ // 1) Check line is empty or not.
+ if( mLines.Empty() )
+ {
+ return 0u;
+ }
+ // 2) Check in the cached line.
const LineRun& lineRun = *( mLines.Begin() + mCachedLineIndex );
-
if( ( lineRun.characterRun.characterIndex <= characterIndex ) &&
( characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters ) )
{
return mCachedLineIndex;
}
- // 2) Is not in the cached line. Check in the other lines.
-
+ // 3) Is not in the cached line. Check in the other lines.
LineIndex index = characterIndex < lineRun.characterRun.characterIndex ? 0u : mCachedLineIndex + 1u;
for( Vector<LineRun>::ConstIterator it = mLines.Begin() + index,
#include "animated-image-visual.h"
// EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/gif-loading.h>
#include <dali/devel-api/adaptor-framework/image-loading.h>
#include <dali/integration-api/debug.h>
+#include <memory>
// INTERNAL INCLUDES
#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
#include <dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h>
#include <dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h>
+#include <dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.h>
#include <dali-toolkit/internal/visuals/image/image-visual.h>
#include <dali-toolkit/devel-api/image-loader/image-atlas.h>
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
namespace Dali
{
/**
* Multi-image Flow of execution
*
- * | DoSetProperties()
+ * | New
+ * | DoSetProperties()
* | LoadFirstBatch()
- * | cache->LoadBatch()
+ * | new cache
+ * | cache->LoadBatch()
* |
* | DoSetOnStage()
+ * | PrepareTextureSet()
+ * | cache->FirstFrame()
* | CreateRenderer() (Doesn't become ready until first frame loads)
+ * | StartFirstFrame()
* |
* | FrameReady(textureSet)
* | start first frame:
AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl, const Property::Map& properties )
{
- AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache );
- visual->mImageUrl = imageUrl;
+ AnimatedImageVisualPtr visual( new AnimatedImageVisual( factoryCache ) );
+ visual->InitializeGif( imageUrl );
visual->SetProperties( properties );
+ if( visual->mFrameCount > 0 )
+ {
+ visual->LoadFirstBatch();
+ }
+
return visual;
}
AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const Property::Array& imageUrls, const Property::Map& properties )
{
- AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache );
+ AnimatedImageVisualPtr visual( new AnimatedImageVisual( factoryCache ) );
visual->mImageUrls = new ImageCache::UrlList();
visual->mImageUrls->reserve( imageUrls.Count() );
urlStore.mUrl = imageUrls[i].Get<std::string>();
visual->mImageUrls->push_back( urlStore );
}
-
+ visual->mFrameCount = imageUrls.Count();
visual->SetProperties( properties );
- // starts loading immediately
+
+ if( visual->mFrameCount > 0 )
+ {
+ visual->LoadFirstBatch();
+ }
+
return visual;
}
AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl )
{
- AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache );
- visual->mImageUrl = imageUrl;
+ AnimatedImageVisualPtr visual( new AnimatedImageVisual( factoryCache ) );
+ visual->InitializeGif( imageUrl );
+
+ if( visual->mFrameCount > 0 )
+ {
+ visual->LoadFirstBatch();
+ }
return visual;
}
+void AnimatedImageVisual::InitializeGif( const VisualUrl& imageUrl )
+{
+ mImageUrl = imageUrl;
+ mGifLoading = GifLoading::New( imageUrl.GetUrl() );
+ mFrameCount = mGifLoading->GetImageCount();
+ mGifLoading->LoadFrameDelays( mFrameDelayContainer );
+}
+
AnimatedImageVisual::AnimatedImageVisual( VisualFactoryCache& factoryCache )
: Visual::Base( factoryCache ),
mFrameDelayTimer(),
mPlacementActor(),
mPixelArea( FULL_TEXTURE_RECT ),
mImageUrl(),
+ mGifLoading( nullptr ),
mCurrentFrameIndex( 0 ),
mImageUrls( NULL ),
mImageCache( NULL ),
mBatchSize( 1 ),
mFrameDelay( 100 ),
mUrlIndex( 0 ),
+ mFrameCount( 0 ),
mImageSize(),
mWrapModeU( WrapMode::DEFAULT ),
mWrapModeV( WrapMode::DEFAULT ),
{
if( mImageUrl.IsValid() )
{
- mImageSize = Dali::GetGifImageSize( mImageUrl.GetUrl() );
+ mImageSize = mGifLoading->GetImageSize();
}
else if( mImageUrls && mImageUrls->size() > 0 )
{
}
}
}
-
- if( mImageUrls && mImageUrls->size() > 0 )
- {
- LoadFirstBatch();
- }
}
void AnimatedImageVisual::DoSetProperty( Property::Index index,
mFrameDelayTimer.Reset();
}
- mTextureRectContainer.Clear();
- mFrameDelayContainer.Clear();
-
actor.RemoveRenderer( mImpl->mRenderer );
mImpl->mRenderer.Reset();
mPlacementActor.Reset();
void AnimatedImageVisual::CreateRenderer()
{
bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
- bool atlasing = (mTextureRectContainer.Count() > 0) ;
+ bool atlasing = false;
Shader shader = ImageVisual::GetImageShader( mFactoryCache, atlasing, defaultWrapMode );
Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
}
mCurrentFrameIndex = 0;
-
- if( mTextureRectContainer.Count() > 0 )
- {
- mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mTextureRectContainer[mCurrentFrameIndex] );
- }
}
void AnimatedImageVisual::LoadFirstBatch()
{
- DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::LoadFirstBatch()\n");
-
// Ensure the batch size and cache size are no bigger than the number of URLs,
// and that the cache is at least as big as the batch size.
- uint16_t numUrls = mImageUrls->size();
- uint16_t batchSize = std::min( mBatchSize, numUrls );
- uint16_t cacheSize = std::min( std::max( batchSize, mCacheSize ), numUrls );
+ uint16_t numUrls = 0;
+ uint16_t batchSize = 1;
+ uint16_t cacheSize = 1;
+
+ if( mImageUrls )
+ {
+ numUrls = mImageUrls->size();
+ }
+ else
+ {
+ numUrls = mFrameCount;
+ }
+
+ batchSize = std::min( mBatchSize, numUrls );
+ cacheSize = std::min( std::max( batchSize, mCacheSize ), numUrls );
+
+ DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::LoadFirstBatch() batchSize:%d cacheSize:%d\n", batchSize, cacheSize);
mUrlIndex = 0;
TextureManager& textureManager = mFactoryCache.GetTextureManager();
- if( batchSize > 0 && cacheSize > 0 )
+ if( mGifLoading != nullptr )
+ {
+ mImageCache = new RollingGifImageCache( textureManager, *mGifLoading, mFrameCount, *this, cacheSize, batchSize );
+ }
+ else if( batchSize > 0 && cacheSize > 0 )
{
if( cacheSize < numUrls )
{
{
mImageCache = new RollingImageCache( textureManager, *mImageUrls, *this, 1, 1 );
}
+ if (!mImageCache)
+ {
+ DALI_LOG_ERROR("mImageCache is null");
+ }
}
void AnimatedImageVisual::StartFirstFrame( TextureSet& textureSet )
mPlacementActor.Reset();
}
- int frameDelay = mFrameDelay;
- if( mFrameDelayContainer.Count() > 1 )
+ mCurrentFrameIndex = 0;
+
+ if( mFrameCount > 1 )
{
- frameDelay = mFrameDelayContainer[0];
- }
- mFrameDelayTimer = Timer::New( frameDelay );
- mFrameDelayTimer.TickSignal().Connect( this, &AnimatedImageVisual::DisplayNextFrame );
- mFrameDelayTimer.Start();
+ int frameDelay = mFrameDelay; // from URL array
+ if( mFrameDelayContainer.Count() > 0 ) // from GIF
+ {
+ frameDelay = mFrameDelayContainer[0];
+ }
- DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"ResourceReady()\n");
+ mFrameDelayTimer = Timer::New( frameDelay );
+ mFrameDelayTimer.TickSignal().Connect( this, &AnimatedImageVisual::DisplayNextFrame );
+ mFrameDelayTimer.Start();
+ }
+ DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"ResourceReady(ResourceStatus::READY)\n");
ResourceReady( Toolkit::Visual::ResourceStatus::READY );
}
TextureSet AnimatedImageVisual::PrepareTextureSet()
{
TextureSet textureSet;
- if( mImageUrl.IsValid() )
+ if (mImageCache)
+ textureSet = mImageCache->FirstFrame();
+ if( textureSet )
{
- textureSet = PrepareAnimatedGifImage();
+ SetImageSize( textureSet );
}
else
{
- textureSet = mImageCache->FirstFrame();
- if( textureSet )
- {
- SetImageSize( textureSet );
- }
- }
- return textureSet;
-}
-
-TextureSet AnimatedImageVisual::PrepareAnimatedGifImage()
-{
- TextureSet textureSet;
-
- // load from image file
- std::vector<Dali::PixelData> pixelDataList;
-
- if( mImageUrl.IsLocalResource() )
- {
- if( Dali::LoadAnimatedGifFromFile( mImageUrl.GetUrl().c_str() , pixelDataList, mFrameDelayContainer ) )
- {
- mImageSize.SetWidth( pixelDataList[0].GetWidth() );
- mImageSize.SetHeight( pixelDataList[0].GetHeight() );
-
- Texture texture = Toolkit::ImageAtlas::PackToAtlas( pixelDataList, mTextureRectContainer );
- textureSet = TextureSet::New();
- textureSet.SetTexture( 0, texture );
- }
+ DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"ResourceReady(ResourceStatus::FAILED)\n");
+ ResourceReady( Toolkit::Visual::ResourceStatus::FAILED );
}
return textureSet;
bool AnimatedImageVisual::DisplayNextFrame()
{
- DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::DisplayNextFrame() start\n");
-
- if( mFrameDelayContainer.Count() > 0 )
+ if( mFrameCount > 1 )
{
// Wrap the frame index
++mCurrentFrameIndex;
- mCurrentFrameIndex %= mFrameDelayContainer.Count();
+ mCurrentFrameIndex %= mFrameCount;
+ }
+ DALI_LOG_INFO( gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::DisplayNextFrame(this:%p) FrameCount:%d\n", this, mCurrentFrameIndex);
- mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mTextureRectContainer[mCurrentFrameIndex] );
+ if( mFrameDelayContainer.Count() > 0 )
+ {
+ unsigned int delay = mFrameDelayContainer[mCurrentFrameIndex];
- if( mFrameDelayTimer.GetInterval() != mFrameDelayContainer[mCurrentFrameIndex] )
+ if( mFrameDelayTimer.GetInterval() != delay )
{
- mFrameDelayTimer.SetInterval( mFrameDelayContainer[mCurrentFrameIndex] );
+ mFrameDelayTimer.SetInterval( delay );
}
}
- else if( mImageCache )
+
+ TextureSet textureSet;
+ if (mImageCache)
+ textureSet = mImageCache->NextFrame();
+ if( textureSet )
{
- TextureSet textureSet = mImageCache->NextFrame();
- if( textureSet )
- {
- SetImageSize( textureSet );
- mImpl->mRenderer.SetTextures( textureSet );
- }
+ SetImageSize( textureSet );
+ mImpl->mRenderer.SetTextures( textureSet );
}
// Keep timer ticking
#include <dali/public-api/math/vector4.h>
#include <dali/public-api/object/weak-handle.h>
#include <dali/public-api/adaptor-framework/timer.h>
+#include <dali/devel-api/adaptor-framework/gif-loading.h>
// INTERNAL INCLUDES
#include <dali-toolkit/internal/visuals/visual-base-impl.h>
/**
* Adds the texture set to the renderer, and the renderer to the
* placement actor, and starts the frame timer
+ * @param[in] textureSet The texture set to apply
*/
void StartFirstFrame( TextureSet& textureSet );
TextureSet PrepareTextureSet();
/**
- * Load the gif image and pack the frames into atlas.
- * @return The atlas texture.
- */
- TextureSet PrepareAnimatedGifImage();
-
- /**
* Set the image size from the texture set
+ * @param[in] textureSet The texture set to get the size from
*/
void SetImageSize( TextureSet& textureSet );
/**
* Called when the next frame is ready.
+ * @param[in] textureSet the texture set to apply
*/
void FrameReady( TextureSet textureSet );
*/
bool DisplayNextFrame();
+ /**
+ * Initialize the gif variables.
+ * @param[in] imageUrl The url of the animated gif
+ */
+ void InitializeGif( const VisualUrl& imageUrl );
// Undefined
AnimatedImageVisual( const AnimatedImageVisual& animatedImageVisual );
WeakHandle<Actor> mPlacementActor;
// Variables for GIF player
- Dali::Vector<Vector4> mTextureRectContainer;
Dali::Vector<uint32_t> mFrameDelayContainer;
Vector4 mPixelArea;
VisualUrl mImageUrl;
+ std::unique_ptr<Dali::GifLoading> mGifLoading; // Only needed for animated gifs
uint32_t mCurrentFrameIndex; // Frame index into textureRects
// Variables for Multi-Image player
uint16_t mUrlIndex;
// Shared variables
+ uint32_t mFrameCount; // Number of frames
ImageDimensions mImageSize;
Dali::WrapMode::Type mWrapModeU:3;
// CLASS HEADER
#include <dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h>
+// INTERNAL HEADERS
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
+
namespace Dali
{
namespace Toolkit
FixedImageCache::FixedImageCache(
TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer,
unsigned int batchSize )
-: ImageCache( textureManager, urlList, observer, batchSize ),
+: ImageCache( textureManager, observer, batchSize ),
+ mImageUrls( urlList ),
mFront(0u)
{
mReadyFlags.reserve( mImageUrls.size() );
// need to account for this inside the UploadComplete method using mRequestingLoad.
mRequestingLoad = true;
- mImageUrls[ mUrlIndex ].mTextureId =
- mTextureManager.RequestLoad( url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
- SamplingMode::BOX_THEN_LINEAR, TextureManager::NO_ATLAS,
- this, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED );
+ bool synchronousLoading = false;
+ bool atlasingStatus = false;
+ bool loadingStatus = false;
+ TextureManager::MaskingDataPointer maskInfo = nullptr;
+ AtlasUploadObserver* atlasObserver = nullptr;
+ ImageAtlasManagerPtr imageAtlasManager = nullptr;
+ Vector4 textureRect;
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+ mTextureManager.LoadTexture(
+ url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR, maskInfo,
+ synchronousLoading, mImageUrls[ mUrlIndex ].mTextureId, textureRect,
+ atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT,
+ Dali::WrapMode::Type::DEFAULT, this,
+ atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED,
+ preMultiply );
+
+ if( loadingStatus == false ) // not loading, means it's already ready.
+ {
+ SetImageFrameReady( mImageUrls[ mUrlIndex ].mTextureId );
+ }
mRequestingLoad = false;
++mUrlIndex;
}
int32_t textureId,
TextureSet textureSet,
bool useAtlasing,
- const Vector4& atlasRect )
+ const Vector4& atlasRect,
+ bool preMultiplied)
{
bool frontFrameReady = IsFrontReady();
namespace Internal
{
-class FixedImageCache : public ImageCache
+class FixedImageCache : public ImageCache, public TextureUploadObserver
{
public:
/**
int32_t textureId,
TextureSet textureSet,
bool useAtlasing,
- const Vector4& atlasRect );
+ const Vector4& atlasRect,
+ bool premultiplied) override;
-protected:
+private:
+ std::vector<UrlStore>& mImageUrls;
std::vector<bool> mReadyFlags;
unsigned int mFront;
};
{
ImageCache::ImageCache( TextureManager& textureManager,
- UrlList& urlList,
ImageCache::FrameReadyObserver& observer,
unsigned int batchSize )
: mTextureManager( textureManager ),
mObserver( observer ),
- mImageUrls( urlList ),
mBatchSize( batchSize ),
mUrlIndex(0u),
mWaitingForReadyFrame(false),
namespace Internal
{
-class ImageCache : public TextureUploadObserver
+class ImageCache
{
public:
/**
* batch and cache sizes. The cache is as large as the number of urls.
*/
ImageCache( TextureManager& textureManager,
- UrlList& urlList,
ImageCache::FrameReadyObserver& observer,
unsigned int batchSize );
protected:
TextureManager& mTextureManager;
FrameReadyObserver& mObserver;
- std::vector<UrlStore>& mImageUrls;
unsigned int mBatchSize;
unsigned int mUrlIndex;
bool mWaitingForReadyFrame:1;
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include "rolling-gif-image-cache.h"
+
+// EXTERNAL HEADERS
+
+// INTERNAL HEADERS
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
+#include <dali/integration-api/debug.h>
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ANIMATED_IMAGE");
+
+#define LOG_CACHE \
+ { \
+ std::ostringstream oss; \
+ oss<<"Size:"<<mQueue.Count()<<" [ "; \
+ for(std::size_t _i=0; _i<mQueue.Count(); ++_i) \
+ { \
+ oss<<_i<< \
+ "={ frm#: " << mQueue[_i].mFrameNumber << \
+ " tex: " << mImageUrls[mQueue[_i].mFrameNumber].mTextureId<<"}, "; \
+ } \
+ oss<<" ]"<<std::endl; \
+ DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"%s",oss.str().c_str()); \
+ }
+
+#else
+ #define LOG_CACHE
+#endif
+
+const bool ENABLE_ORIENTATION_CORRECTION( true );
+
+}
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+RollingGifImageCache::RollingGifImageCache(
+ TextureManager& textureManager, GifLoading& gifLoading, uint32_t frameCount, ImageCache::FrameReadyObserver& observer,
+ uint16_t cacheSize, uint16_t batchSize )
+: ImageCache( textureManager, observer, batchSize ),
+ mGifLoading( gifLoading ),
+ mFrameCount( frameCount ),
+ mFrameIndex( 0 ),
+ mCacheSize( cacheSize ),
+ mQueue( cacheSize )
+{
+ mImageUrls.resize( mFrameCount );
+ LoadBatch();
+}
+
+RollingGifImageCache::~RollingGifImageCache()
+{
+ while( !mQueue.IsEmpty() )
+ {
+ ImageFrame imageFrame = mQueue.PopFront();
+ Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl );
+ }
+}
+
+TextureSet RollingGifImageCache::FirstFrame()
+{
+ return GetFrontTextureSet();
+}
+
+TextureSet RollingGifImageCache::NextFrame()
+{
+ TextureSet textureSet;
+
+ ImageFrame imageFrame = mQueue.PopFront();
+ Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl );
+ mImageUrls[ imageFrame.mFrameNumber ].mTextureId = TextureManager::INVALID_TEXTURE_ID;
+
+ LoadBatch();
+
+ return GetFrontTextureSet();
+}
+
+bool RollingGifImageCache::IsFrontReady() const
+{
+ return ( !mQueue.IsEmpty() );
+}
+
+void RollingGifImageCache::LoadBatch()
+{
+ // Try and load up to mBatchSize images, until the cache is filled.
+ // Once the cache is filled, as frames progress, the old frame is
+ // removed, and another frame is loaded
+
+ std::vector<Dali::PixelData> pixelDataList;
+
+ // Get the smallest number of frames we need to load
+ int batchSize = std::min( std::size_t(mBatchSize), mCacheSize - mQueue.Count() );
+ DALI_LOG_INFO( gAnimImgLogFilter, Debug::Concise, "RollingGifImageCache::LoadBatch() mFrameIndex:%d batchSize:%d\n", mFrameIndex, batchSize );
+
+ if( mGifLoading.LoadNextNFrames( mFrameIndex, batchSize, pixelDataList) )
+ {
+ unsigned int pixelDataListCount = pixelDataList.size();
+
+ for( unsigned int i = 0; i < pixelDataListCount && !mQueue.IsFull(); ++i )
+ {
+ ImageFrame imageFrame;
+
+ // create the texture for uploading the pixel data
+ Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
+ pixelDataList[i].GetPixelFormat(),
+ pixelDataList[i].GetWidth(),
+ pixelDataList[i].GetHeight() );
+
+ texture.Upload( pixelDataList[i] );
+
+ mImageUrls[ mUrlIndex ].mUrl = Dali::Toolkit::TextureManager::AddTexture(texture);
+ imageFrame.mFrameNumber = mUrlIndex;
+
+ ++mUrlIndex;
+ mUrlIndex %= mImageUrls.size();
+
+ mQueue.PushBack( imageFrame );
+
+ bool synchronousLoading = false;
+ bool atlasingStatus = false;
+ bool loadingStatus = false;
+ TextureManager::MaskingDataPointer maskInfo = nullptr;
+ AtlasUploadObserver* atlasObserver = nullptr;
+ ImageAtlasManagerPtr imageAtlasManager = nullptr;
+ Vector4 textureRect;
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+ mTextureManager.LoadTexture(
+ mImageUrls[ imageFrame.mFrameNumber ].mUrl, ImageDimensions(), FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR, maskInfo,
+ synchronousLoading, mImageUrls[ imageFrame.mFrameNumber ].mTextureId, textureRect,
+ atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT,
+ Dali::WrapMode::Type::DEFAULT, NULL,
+ atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply );
+ }
+
+ mFrameIndex += batchSize;
+ mFrameIndex %= mFrameCount;
+ }
+
+ LOG_CACHE;
+}
+
+TextureSet RollingGifImageCache::GetFrontTextureSet() const
+{
+ DALI_LOG_INFO( gAnimImgLogFilter, Debug::Concise, "RollingGifImageCache::GetFrontTextureSet() FrameNumber:%d\n", mQueue[ 0 ].mFrameNumber );
+
+ TextureManager::TextureId textureId = GetCachedTextureId( 0 );
+ return mTextureManager.GetTextureSet( textureId );
+}
+
+TextureManager::TextureId RollingGifImageCache::GetCachedTextureId( int index ) const
+{
+ return mImageUrls[ mQueue[ index ].mFrameNumber ].mTextureId;
+}
+
+} //namespace Internal
+} //namespace Toolkit
+} //namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_INTERNAL_ROLLING_GIF_IMAGE_CACHE_H
+#define DALI_TOOLKIT_INTERNAL_ROLLING_GIF_IMAGE_CACHE_H
+
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/gif-loading.h>
+#include <dali/devel-api/common/circular-queue.h>
+#include <dali-toolkit/internal/visuals/animated-image/image-cache.h>
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+/**
+ * Class to manage a rolling cache of GIF images, where the cache size
+ * is smaller than the total number of images.
+ *
+ * Frames are always ready, so the observer.FrameReady callback is never triggered;
+ * the FirstFrame and NextFrame APIs will always return a texture.
+ */
+class RollingGifImageCache : public ImageCache
+{
+public:
+ /**
+ * Constructor.
+ * @param[in] textureManager The texture manager
+ * @param[in] gifLoader The loaded gif image
+ * @param[in] frameCount The number of frames in the gif
+ * @param[in] observer FrameReady observer
+ * @param[in] cacheSize The size of the cache
+ * @param[in] batchSize The size of a batch to load
+ *
+ * This will start loading textures immediately, according to the
+ * batch and cache sizes.
+ */
+ RollingGifImageCache( TextureManager& textureManager,
+ GifLoading& gifLoader,
+ uint32_t frameCount,
+ ImageCache::FrameReadyObserver& observer,
+ uint16_t cacheSize,
+ uint16_t batchSize );
+
+ /**
+ * Destructor
+ */
+ virtual ~RollingGifImageCache();
+
+ /**
+ * Get the first frame. If it's not ready, this will trigger the
+ * sending of FrameReady() when the image becomes ready.
+ */
+ virtual TextureSet FirstFrame();
+
+ /**
+ * Get the next frame. If it's not ready, this will trigger the
+ * sending of FrameReady() when the image becomes ready.
+ * This will trigger the loading of the next batch.
+ */
+ virtual TextureSet NextFrame();
+
+private:
+ /**
+ * @return true if the front frame is ready
+ */
+ bool IsFrontReady() const;
+
+ /**
+ * Load the next batch of images
+ */
+ void LoadBatch();
+
+ /**
+ * Get the texture set of the front frame.
+ * @return the texture set
+ */
+ TextureSet GetFrontTextureSet() const;
+
+ /**
+ * Get the texture id of the given index
+ */
+ TextureManager::TextureId GetCachedTextureId( int index ) const;
+
+private:
+ /**
+ * Secondary class to hold readiness and index into url
+ */
+ struct ImageFrame
+ {
+ unsigned int mFrameNumber = 0u;
+ };
+
+ GifLoading& mGifLoading;
+ uint32_t mFrameCount;
+ int mFrameIndex;
+ std::vector<UrlStore> mImageUrls;
+ uint16_t mCacheSize;
+ CircularQueue<ImageFrame> mQueue;
+};
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
+
+#endif
#include <dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h>
// INTERNAL HEADERS
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
#include <dali/integration-api/debug.h>
// EXTERNAL HEADERS
RollingImageCache::RollingImageCache(
TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer,
uint16_t cacheSize, uint16_t batchSize )
-: ImageCache( textureManager, urlList, observer, batchSize ),
+: ImageCache( textureManager, observer, batchSize ),
+ mImageUrls( urlList ),
mQueue( cacheSize )
{
LoadBatch();
// need to account for this inside the UploadComplete method using mRequestingLoad.
mRequestingLoad = true;
- mImageUrls[ imageFrame.mUrlIndex ].mTextureId =
- mTextureManager.RequestLoad( url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
- SamplingMode::BOX_THEN_LINEAR, TextureManager::NO_ATLAS,
- this, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED );
+ bool synchronousLoading = false;
+ bool atlasingStatus = false;
+ bool loadingStatus = false;
+ TextureManager::MaskingDataPointer maskInfo = nullptr;
+ AtlasUploadObserver* atlasObserver = nullptr;
+ ImageAtlasManagerPtr imageAtlasManager = nullptr;
+ Vector4 textureRect;
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+ mTextureManager.LoadTexture(
+ url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
+ SamplingMode::BOX_THEN_LINEAR, maskInfo,
+ synchronousLoading, mImageUrls[ imageFrame.mUrlIndex ].mTextureId, textureRect,
+ atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT,
+ Dali::WrapMode::Type::DEFAULT, this,
+ atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED,
+ preMultiply );
+
mRequestingLoad = false;
}
int32_t textureId,
TextureSet textureSet,
bool useAtlasing,
- const Vector4& atlasRect )
+ const Vector4& atlasRect,
+ bool preMultiplied )
{
DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::UploadComplete(textureId:%d) start\n", textureId);
LOG_CACHE;
#define DALI_TOOLKIT_INTERNAL_ROLLING_IMAGE_CACHE_H
/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
* Class to manage a rolling cache of images, where the cache size
* is smaller than the total number of images.
*/
-class RollingImageCache : public ImageCache
+class RollingImageCache : public ImageCache, public TextureUploadObserver
{
public:
/**
int32_t textureId,
TextureSet textureSet,
bool useAtlasing,
- const Vector4& atlasRect );
+ const Vector4& atlasRect,
+ bool preMultiplied ) override;
private:
/**
*/
struct ImageFrame
{
- unsigned int mUrlIndex;
- bool mReady;
+ unsigned int mUrlIndex = 0u;
+ bool mReady = false;
};
+ std::vector<UrlStore>& mImageUrls;
CircularQueue<ImageFrame> mQueue;
};
//INTERNAL INCLUDES
#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
#include <dali-toolkit/internal/visuals/visual-string-constants.h>
}
ColorVisual::ColorVisual( VisualFactoryCache& factoryCache )
-: Visual::Base( factoryCache )
+: Visual::Base( factoryCache ),
+ mRenderIfTransparent( false )
{
}
DALI_LOG_ERROR("ColorVisual: mixColor property has incorrect type\n");
}
}
+
+ Property::Value* renderIfTransparentValue = propertyMap.Find( Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT, RENDER_IF_TRANSPARENT_NAME );
+ if( renderIfTransparentValue )
+ {
+ if( ! renderIfTransparentValue->Get( mRenderIfTransparent ) )
+ {
+ DALI_LOG_ERROR( "ColorVisual: renderIfTransparent property has incorrect type: %d\n", renderIfTransparentValue->GetType() );
+ }
+ }
}
void ColorVisual::DoSetOnStage( Actor& actor )
{
InitializeRenderer();
- actor.AddRenderer( mImpl->mRenderer );
+ // Only add the renderer if it's not fully transparent
+ // We cannot avoid creating a renderer as it's used in the base class
+ if( mRenderIfTransparent || mImpl->mMixColor.a > 0.0f )
+ {
+ actor.AddRenderer( mImpl->mRenderer );
+ }
// Color Visual generated and ready to display
ResourceReady( Toolkit::Visual::ResourceStatus::READY );
map.Clear();
map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR );
map.Insert( Toolkit::ColorVisual::Property::MIX_COLOR, mImpl->mMixColor );
+ map.Insert( Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT, mRenderIfTransparent );
}
void ColorVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
#define DALI_TOOLKIT_INTERNAL_COLOR_VISUAL_H
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// Undefined
ColorVisual& operator=( const ColorVisual& colorRenderer );
+
+private:
+
+ bool mRenderIfTransparent; ///< Whether we should render even if the mix-color is transparent.
};
} // namespace Internal
//Register transform properties
mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+
+ if( IsPreMultipliedAlphaEnabled() )
+ {
+ EnablePreMultipliedAlpha( true );
+ }
}
void ImageVisual::CreateNativeImageRenderer( NativeImage& nativeImage )
mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
}
-
bool ImageVisual::IsSynchronousResourceLoading() const
{
return mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
atlasUploadObserver = this;
}
+ auto preMultiplyOnLoad = mFactoryCache.GetPreMultiplyOnLoad()
+ ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
+ : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
textures = textureManager.LoadTexture( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode,
mMaskingData, IsSynchronousResourceLoading(), mTextureId,
atlasRect, atlasing, mLoading, mWrapModeU,
mWrapModeV, textureObserver, atlasUploadObserver, atlasManager,
- mOrientationCorrection,
- forceReload );
+ mOrientationCorrection, forceReload, preMultiplyOnLoad);
+
+ if( textures && preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD)
+ {
+ EnablePreMultipliedAlpha( true );
+ }
if( atlasing ) // Flag needs to be set before creating renderer
{
// From Texture Manager
void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, TextureSet textureSet, bool usingAtlas,
- const Vector4& atlasRectangle )
+ const Vector4& atlasRectangle, bool preMultiplied )
{
Toolkit::Visual::ResourceStatus resourceStatus;
Actor actor = mPlacementActor.GetHandle();
{
mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mAtlasRect );
}
+ else if( preMultiplied )
+ {
+ EnablePreMultipliedAlpha( true );
+ }
actor.AddRenderer( mImpl->mRenderer );
// reset the weak handle so that the renderer only get added to actor once
* To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready.
* This callback is the place to add the renderer as it would be called once the loading is finished.
*/
- virtual void UploadCompleted();
+ virtual void UploadCompleted() override;
/**
* @copydoc TextureUploadObserver::UploadCompleted
* To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready.
* This callback is the place to add the renderer as it would be called once the loading is finished.
*/
- virtual void UploadComplete( bool success, int32_t textureId, TextureSet textureSet, bool usingAtlas, const Vector4& atlasRectangle );
+ virtual void UploadComplete( bool success, int32_t textureId, TextureSet textureSet,
+ bool usingAtlas, const Vector4& atlasRectangle, bool preMultiplied ) override;
private:
#include <dali-toolkit/internal/text/text-effects-style.h>
#include <dali-toolkit/internal/text/script-run.h>
#include <dali-toolkit/internal/text/text-enumerations-impl.h>
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
namespace Dali
{
const bool styleEnabled = ( shadowEnabled || underlineEnabled || outlineEnabled );
- TextureSet textureSet = GetTextTexture( relayoutSize, hasMultipleTextColors, containsEmoji, styleEnabled );
+ TextureSet textureSet = GetTextTexture( mImpl->mTransform.mSize, hasMultipleTextColors, containsEmoji, styleEnabled );
mImpl->mRenderer.SetTextures( textureSet );
Shader shader = GetTextShader( mFactoryCache, hasMultipleTextColors, containsEmoji, styleEnabled );
// Create RGBA texture if the text contains emojis or multiple text colors, otherwise L8 texture
Pixel::Format textPixelFormat = ( containsEmoji || hasMultipleTextColors ) ? Pixel::RGBA8888 : Pixel::L8;
+ // Check the text direction
+ Toolkit::DevelText::TextDirection::Type textDirection = mController->GetTextDirection();
+
// Create a texture for the text without any styles
- PixelData data = mTypesetter->Render( size, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat );
+ PixelData data = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat );
// It may happen the image atlas can't handle a pixel data it exceeds the maximum size.
// In that case, create a texture. TODO: should tile the text.
if ( styleEnabled )
{
// Create RGBA texture for all the text styles (without the text itself)
- PixelData styleData = mTypesetter->Render( size, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888 );
+ PixelData styleData = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888 );
Texture styleTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
styleData.GetPixelFormat(),
if ( containsEmoji && !hasMultipleTextColors )
{
// Create a L8 texture as a mask to avoid color glyphs (e.g. emojis) to be affected by text color animation
- PixelData maskData = mTypesetter->Render( size, Text::Typesetter::RENDER_MASK, false, Pixel::L8 );
+ PixelData maskData = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_MASK, false, Pixel::L8 );
Texture maskTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
maskData.GetPixelFormat(),
const int INVALID_INDEX( -1 ); ///< Invalid index used to represent a non-existant TextureInfo struct
const int INVALID_CACHE_INDEX( -1 ); ///< Invalid Cache index
+
+void PreMultiply( Devel::PixelBuffer pixelBuffer, TextureManager::MultiplyOnLoad& preMultiplyOnLoad )
+{
+ if( Pixel::HasAlpha( pixelBuffer.GetPixelFormat() ) )
+ {
+ if( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD )
+ {
+ pixelBuffer.MultiplyColorByAlpha();
+ }
+ }
+ else
+ {
+ preMultiplyOnLoad = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+ }
+}
+
} // Anonymous namespace
TextureManager::MaskingData::MaskingData()
}
TextureSet TextureManager::LoadTexture(
- VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode,
+ const VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode,
Dali::SamplingMode::Type samplingMode, const MaskingDataPointer& maskInfo,
bool synchronousLoading, TextureManager::TextureId& textureId, Vector4& textureRect,
bool& atlasingStatus, bool& loadingStatus, Dali::WrapMode::Type wrapModeU,
Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver,
AtlasUploadObserver* atlasObserver, ImageAtlasManagerPtr imageAtlasManager, bool orientationCorrection,
- TextureManager::ReloadPolicy reloadPolicy )
+ TextureManager::ReloadPolicy reloadPolicy, TextureManager::MultiplyOnLoad& preMultiplyOnLoad )
{
TextureSet textureSet;
{
if( elem.textureId == id )
{
+ textureId = elem.textureId;
return elem.textureSet;
}
}
orientationCorrection );
if( pixelBuffer )
{
+ PreMultiply( pixelBuffer, preMultiplyOnLoad );
data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
}
}
Devel::PixelBuffer pixelBuffer = LoadImageFromFile( BROKEN_IMAGE_URL );
if( pixelBuffer )
{
+ PreMultiply( pixelBuffer, preMultiplyOnLoad );
data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
}
Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(),
if( !maskInfo )
{
textureId = RequestLoad( url, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS,
- textureObserver, orientationCorrection, reloadPolicy );
+ textureObserver, orientationCorrection, reloadPolicy, preMultiplyOnLoad );
}
else
{
maskInfo->mCropToMask,
textureObserver,
orientationCorrection,
- reloadPolicy );
+ reloadPolicy, preMultiplyOnLoad );
}
- TextureManager::LoadState loadState = GetTextureState( textureId );
+ TextureManager::LoadState loadState = GetTextureStateInternal( textureId );
loadingStatus = ( loadState == TextureManager::LOADING );
if( loadState == TextureManager::UPLOADED )
}
TextureManager::TextureId TextureManager::RequestLoad(
- const VisualUrl& url,
- const ImageDimensions desiredSize,
- FittingMode::Type fittingMode,
- Dali::SamplingMode::Type samplingMode,
- const UseAtlas useAtlas,
- TextureUploadObserver* observer,
- bool orientationCorrection,
- TextureManager::ReloadPolicy reloadPolicy )
+ const VisualUrl& url,
+ const ImageDimensions desiredSize,
+ FittingMode::Type fittingMode,
+ Dali::SamplingMode::Type samplingMode,
+ const UseAtlas useAtlas,
+ TextureUploadObserver* observer,
+ bool orientationCorrection,
+ TextureManager::ReloadPolicy reloadPolicy,
+ TextureManager::MultiplyOnLoad& preMultiplyOnLoad )
{
return RequestLoadInternal( url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas,
- false, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy );
+ false, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy,
+ preMultiplyOnLoad );
}
TextureManager::TextureId TextureManager::RequestLoad(
- const VisualUrl& url,
- TextureId maskTextureId,
- float contentScale,
- const ImageDimensions desiredSize,
- FittingMode::Type fittingMode,
- Dali::SamplingMode::Type samplingMode,
- const UseAtlas useAtlas,
- bool cropToMask,
- TextureUploadObserver* observer,
- bool orientationCorrection,
- TextureManager::ReloadPolicy reloadPolicy )
+ const VisualUrl& url,
+ TextureId maskTextureId,
+ float contentScale,
+ const ImageDimensions desiredSize,
+ FittingMode::Type fittingMode,
+ Dali::SamplingMode::Type samplingMode,
+ const UseAtlas useAtlas,
+ bool cropToMask,
+ TextureUploadObserver* observer,
+ bool orientationCorrection,
+ TextureManager::ReloadPolicy reloadPolicy,
+ TextureManager::MultiplyOnLoad& preMultiplyOnLoad )
{
return RequestLoadInternal( url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas,
- cropToMask, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy );
+ cropToMask, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy,
+ preMultiplyOnLoad );
}
TextureManager::TextureId TextureManager::RequestMaskLoad( const VisualUrl& maskUrl )
{
// Use the normal load procedure to get the alpha mask.
+ auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
return RequestLoadInternal( maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL,
SamplingMode::NO_FILTER, NO_ATLAS, false, KEEP_PIXEL_BUFFER, NULL, true,
- TextureManager::ReloadPolicy::CACHED );
+ TextureManager::ReloadPolicy::CACHED, preMultiply );
}
TextureManager::TextureId TextureManager::RequestLoadInternal(
- const VisualUrl& url,
+ const VisualUrl& url,
TextureId maskTextureId,
float contentScale,
const ImageDimensions desiredSize,
StorageType storageType,
TextureUploadObserver* observer,
bool orientationCorrection,
- TextureManager::ReloadPolicy reloadPolicy )
+ TextureManager::ReloadPolicy reloadPolicy,
+ TextureManager::MultiplyOnLoad& preMultiplyOnLoad)
{
// First check if the requested Texture is cached.
const TextureHash textureHash = GenerateHash( url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas,
- maskTextureId );
+ maskTextureId, preMultiplyOnLoad );
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 );
+ maskTextureId, preMultiplyOnLoad );
// Check if the requested Texture exists in the cache.
if( cacheIndex != INVALID_CACHE_INDEX )
{
// 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 ) );
+ false, cropToMask, useAtlas, textureHash, orientationCorrection,
+ preMultiply ) );
cacheIndex = mTextureInfoContainer.size() - 1u;
DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n",
// The Texture has already loaded. The other observers have already been notified.
// We need to send a "late" loaded notification for this observer.
observer->UploadComplete( true, textureInfo.textureId, textureInfo.textureSet,
- textureInfo.useAtlas, textureInfo.atlasRect );
+ textureInfo.useAtlas, textureInfo.atlasRect,
+ textureInfo.preMultiplied );
}
break;
}
TextureInfo& cachedTextureInfo( mTextureInfoContainer[ cacheIndex ] );
loadState = cachedTextureInfo.loadState;
}
+ else
+ {
+ for( auto&& elem : mExternalTextures )
+ {
+ if( elem.textureId == textureId )
+ {
+ loadState = LoadState::UPLOADED;
+ break;
+ }
+ }
+ }
+ return loadState;
+}
+
+TextureManager::LoadState TextureManager::GetTextureStateInternal( TextureId textureId )
+{
+ LoadState loadState = TextureManager::NOT_STARTED;
+
+ int cacheIndex = GetCacheIndexFromId( textureId );
+ if( cacheIndex != INVALID_CACHE_INDEX )
+ {
+ TextureInfo& cachedTextureInfo( mTextureInfoContainer[ cacheIndex ] );
+ loadState = cachedTextureInfo.loadState;
+ }
+
return loadState;
}
TextureInfo& cachedTextureInfo( mTextureInfoContainer[ cacheIndex ] );
textureSet = cachedTextureInfo.textureSet;
}
+ else
+ {
+ for( auto&& elem : mExternalTextures )
+ {
+ if( elem.textureId == textureId )
+ {
+ textureSet = elem.textureSet;
+ break;
+ }
+ }
+ }
return textureSet;
}
// wait for the mask to finish loading.
if( textureInfo.maskTextureId != INVALID_TEXTURE_ID )
{
- LoadState maskLoadState = GetTextureState( textureInfo.maskTextureId );
+ LoadState maskLoadState = GetTextureStateInternal( textureInfo.maskTextureId );
if( maskLoadState == LOADING )
{
textureInfo.pixelBuffer = pixelBuffer; // Store the pixel buffer temporarily
pixelBuffer.ApplyMask( maskPixelBuffer, contentScale, cropToMask );
}
+
void TextureManager::UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo )
{
if( textureInfo.useAtlas != USE_ATLAS )
{
DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, " TextureManager::UploadTexture() New Texture for textureId:%d\n", textureInfo.textureId );
+ // If the texture doesn't have an alpha channel, can't pre-multiply it.
+ // Ensure that we don't change the load parameter (it's used for hashing), and instead set
+ // the status for use in the observer.
+ auto preMultiply = textureInfo.preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD :
+ TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+ PreMultiply( pixelBuffer, preMultiply );
+ textureInfo.preMultiplied = (preMultiply == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD );
+
Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(),
pixelBuffer.GetWidth(), pixelBuffer.GetHeight() );
+
PixelData pixelData = Devel::PixelBuffer::Convert( pixelBuffer );
texture.Upload( pixelData );
if ( ! textureInfo.textureSet )
// because new load requests can modify the mTextureInfoContainer list
// (e.g. if more requests are pushed back it can cause the list to be
// resized invalidating the reference to the TextureInfo ).
- observer->UploadComplete( success, info->textureId, info->textureSet, info->useAtlas, info->atlasRect );
+ observer->UploadComplete( success, info->textureId, info->textureSet, info->useAtlas, info->atlasRect,
+ info->preMultiplied );
observer->DestructionSignal().Disconnect( this, &TextureManager::ObserverDestroyed );
// Get the textureInfo from the container again as it may have been
}
}
- DALI_LOG_WARNING( "Cannot locate TextureId: %d\n", textureId );
return INVALID_CACHE_INDEX;
}
const FittingMode::Type fittingMode,
const Dali::SamplingMode::Type samplingMode,
const UseAtlas useAtlas,
- TextureId maskTextureId )
+ TextureId maskTextureId,
+ TextureManager::MultiplyOnLoad preMultiplyOnLoad)
{
std::string hashTarget( url );
const size_t urlLength = hashTarget.length();
if( maskTextureId != INVALID_TEXTURE_ID )
{
- hashTarget.resize( urlLength + sizeof( TextureId ) );
- TextureId* hashTargetPtr = reinterpret_cast<TextureId*>(&( hashTarget[ urlLength ] ));
+ auto textureIdIndex = hashTarget.length();
+ hashTarget.resize( hashTarget.length() + sizeof( TextureId ) );
+ unsigned char* hashTargetPtr = reinterpret_cast<unsigned char*>(&( hashTarget[ textureIdIndex ] ));
- // Append the hash target to the end of the URL byte by byte:
+ // Append the texture id to the end of the URL byte by byte:
// (to avoid SIGBUS / alignment issues)
for( size_t byteIter = 0; byteIter < sizeof( TextureId ); ++byteIter )
{
}
}
+ auto premultipliedIndex = hashTarget.length();
+ hashTarget.resize( premultipliedIndex + 1 );
+ switch( preMultiplyOnLoad )
+ {
+ case TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD:
+ {
+ hashTarget[ premultipliedIndex ] = 't';
+ break;
+ }
+ case TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY:
+ {
+ hashTarget[ premultipliedIndex ] = 'f';
+ break;
+ }
+ }
+
return Dali::CalculateHash( hashTarget );
}
const FittingMode::Type fittingMode,
const Dali::SamplingMode::Type samplingMode,
const bool useAtlas,
- TextureId maskTextureId)
+ TextureId maskTextureId,
+ TextureManager::MultiplyOnLoad preMultiplyOnLoad )
{
// Default to an invalid ID, in case we do not find a match.
int cacheIndex = INVALID_CACHE_INDEX;
{
// We have a match, now we check all the original parameters in case of a hash collision.
TextureInfo& textureInfo( mTextureInfoContainer[i] );
+ auto multiplyOnLoad = textureInfo.preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD :
+ TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
if( ( url == textureInfo.url.GetUrl() ) &&
( useAtlas == textureInfo.useAtlas ) &&
( maskTextureId == textureInfo.maskTextureId ) &&
( size == textureInfo.desiredSize ) &&
+ ( preMultiplyOnLoad == multiplyOnLoad ) &&
( ( size.GetWidth() == 0 && size.GetHeight() == 0 ) ||
( fittingMode == textureInfo.fittingMode &&
samplingMode == textureInfo.samplingMode ) ) )
}
}
+
TextureManager::AsyncLoadingHelper::AsyncLoadingHelper(TextureManager& textureManager)
: AsyncLoadingHelper(Toolkit::AsyncImageLoader::New(), textureManager,
AsyncLoadingInfoContainerType())
};
/**
- * @breif Types of reloading policies
- */
+ * @brief Types of reloading policies
+ */
enum class ReloadPolicy
{
CACHED = 0, ///< Loads cached texture if it exists.
FORCED ///< Forces reloading of texture.
};
+ /**
+ * @brief Whether to multiply alpha into color channels on load
+ */
+ enum class MultiplyOnLoad
+ {
+ LOAD_WITHOUT_MULTIPLY = 0, ///< Don't modify the image
+ MULTIPLY_ON_LOAD ///< Multiply alpha into color channels on load
+ };
+
public:
struct MaskingData
// TextureManager Main API:
- TextureSet LoadTexture(VisualUrl& url, Dali::ImageDimensions desiredSize,
- Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode,
- const MaskingDataPointer& maskInfo, bool synchronousLoading,
- TextureManager::TextureId& textureId, Vector4& textureRect,
- bool& atlasingStatus, bool& loadingStatus, Dali::WrapMode::Type wrapModeU,
- Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver,
- AtlasUploadObserver* atlasObserver,
- ImageAtlasManagerPtr imageAtlasManager,
- bool orientationCorrection,
- TextureManager::ReloadPolicy reloadPolicy );
+ /**
+ * @brief Requests an image load of the given URL.
+ *
+ * The parameters are used to specify how the image is loaded.
+ * The observer has the UploadComplete method called when the load is ready.
+ *
+ * When the client has finished with the Texture, Remove() should be called.
+ *
+ * @param[in] url The URL of the image to load
+ * @param[in] desiredSize The size the image is likely to appear at. This can be set to 0,0 for automatic
+ * @param[in] fittingMode The FittingMode to use
+ * @param[in] samplingMode The SamplingMode to use
+ * @param[in] maskInfo Mask info structure
+ * @param[in] synchronousLoading true if the URL should be loaded synchronously
+ * @param[out] textureId, The textureId of the URL
+ * @param[out] textureRect The rectangle within the texture atlas that this URL occupies
+ * @param[in,out] atlasingStatus Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still
+ * be loaded, and marked successful, but this will be set to false.
+ * If atlasing succeeds, this will be set to true.
+ * @param[out] loadingStatus The loading status of the texture
+ * @param[in] wrapModeU Horizontal Wrap mode
+ * @param[in] wrapModeV Vertical Wrap mode
+ * @param[in] textureObserver The client object should inherit from this and provide the "UploadCompleted" virtual.
+ * This is called when an image load completes (or fails).
+ * @param[in] atlasObserver This is used if the texture is atlased, and will be called instead of
+ * textureObserver.UploadCompleted
+ * @param[in] imageAtlasManager The atlas manager to use for atlasing textures
+ * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
+ * @param[in] reloadPolicy Forces a reload of the texture even if already cached
+ * @param[in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
+ * image has no alpha channel
+ *
+ * @return The texture set containing the image, or empty if still loading.
+ */
+
+ TextureSet LoadTexture( const VisualUrl& url,
+ Dali::ImageDimensions desiredSize,
+ Dali::FittingMode::Type fittingMode,
+ Dali::SamplingMode::Type samplingMode,
+ const MaskingDataPointer& maskInfo,
+ bool synchronousLoading,
+ TextureManager::TextureId& textureId,
+ Vector4& textureRect,
+ bool& atlasingStatus,
+ bool& loadingStatus,
+ Dali::WrapMode::Type wrapModeU,
+ Dali::WrapMode::Type wrapModeV,
+ TextureUploadObserver* textureObserver,
+ AtlasUploadObserver* atlasObserver,
+ ImageAtlasManagerPtr imageAtlasManager,
+ bool orientationCorrection,
+ TextureManager::ReloadPolicy reloadPolicy,
+ MultiplyOnLoad& preMultiplyOnLoad );
/**
* @brief Requests an image load of the given URL.
* This is called when an image load completes (or fails).
* @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
* @param[in] reloadPolicy Forces a reload of the texture even if already cached
+ * @param[in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the image has no alpha channel
* @return A TextureId to use as a handle to reference this Texture
*/
TextureId RequestLoad( const VisualUrl& url,
const UseAtlas useAtlasing,
TextureUploadObserver* observer,
bool orientationCorrection,
- TextureManager::ReloadPolicy reloadPolicy );
+ TextureManager::ReloadPolicy reloadPolicy,
+ MultiplyOnLoad& preMultiplyOnLoad );
/**
* @brief Requests an image load of the given URL, when the texture has
* This is called when an image load completes (or fails).
* @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
* @param[in] reloadPolicy Forces a reload of the texture even if already cached
+ * @param[in] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
+ * image has no alpha channel
* @return A TextureId to use as a handle to reference this Texture
*/
TextureId RequestLoad( const VisualUrl& url,
bool cropToMask,
TextureUploadObserver* observer,
bool orientationCorrection,
- TextureManager::ReloadPolicy reloadPolicy );
+ TextureManager::ReloadPolicy reloadPolicy,
+ MultiplyOnLoad& preMultiplyOnLoad );
/**
* Requests a masking image to be loaded. This mask is not uploaded to GL,
* This is called when an image load completes (or fails).
* @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
* @param[in] reloadPolicy Forces a reload of the texture even if already cached
+ * @param[in] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if
+ * there is no alpha
* @return A TextureId to use as a handle to reference this Texture
*/
TextureId RequestLoadInternal(
StorageType storageType,
TextureUploadObserver* observer,
bool orientationCorrection,
- TextureManager::ReloadPolicy reloadPolicy );
+ TextureManager::ReloadPolicy reloadPolicy,
+ MultiplyOnLoad& preMultiplyOnLoad );
+ /**
+ * @brief Get the current state of a texture
+ * @param[in] textureId The texture id to query
+ * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
+ * is not valid.
+ */
+ LoadState GetTextureStateInternal( TextureId textureId );
typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
bool cropToMask,
UseAtlas useAtlas,
TextureManager::TextureHash hash,
- bool orientationCorrection )
+ bool orientationCorrection,
+ bool preMultiplyOnLoad )
: url( url ),
desiredSize( desiredSize ),
useSize( desiredSize ),
loadSynchronously( loadSynchronously ),
useAtlas( useAtlas ),
cropToMask( cropToMask ),
- orientationCorrection( true )
+ orientationCorrection( true ),
+ preMultiplyOnLoad( preMultiplyOnLoad ),
+ preMultiplied( false )
{
}
///< This is updated to false if atlas is not used
bool cropToMask:1; ///< true if the image should be cropped to the mask size.
bool orientationCorrection:1; ///< true if the image should be rotated to match exif orientation data
+ bool preMultiplyOnLoad:1; ///< true if the image's color should be multiplied by it's alpha
+ bool preMultiplied:1; ///< true if the image's color was multiplied by it's alpha
};
// Structs:
TextureHash GenerateHash( const std::string& url, const ImageDimensions size,
const FittingMode::Type fittingMode,
const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas,
- TextureId maskTextureId );
+ TextureId maskTextureId,
+ MultiplyOnLoad preMultiplyOnLoad);
/**
* @brief Looks up a cached texture by its hash.
* If found, the given parameters are used to check there is no hash-collision.
const FittingMode::Type fittingMode,
const Dali::SamplingMode::Type samplingMode,
const bool useAtlas,
- TextureId maskTextureId );
+ TextureId maskTextureId,
+ MultiplyOnLoad preMultiplyOnLoad);
private:
RoundRobinContainerView< AsyncLoadingHelper > mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads
std::vector< ExternalTextureInfo > mExternalTextures; ///< Externally provided textures
TextureId mCurrentTextureId; ///< The current value used for the unique Texture Id generation
-
};
* @param[in] textureSet The TextureSet containing the Texture
* @param[in] useAtlasing True if atlasing was used (note: this may be different to what was requested)
* @param[in] atlasRect If using atlasing, this is the rectangle within the atlas to use.
+ * @param[in] preMultiplied True if the image had pre-multiplied alpha applied
*/
- virtual void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect ) = 0;
+ virtual void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing,
+ const Vector4& atlasRect, bool preMultiplied ) = 0;
/**
* @brief Returns the destruction signal.
namespace Internal
{
-VisualFactoryCache::VisualFactoryCache()
-: mSvgRasterizeThread( NULL )
+VisualFactoryCache::VisualFactoryCache( bool preMultiplyOnLoad )
+: mSvgRasterizeThread( NULL ),
+ mPreMultiplyOnLoad( preMultiplyOnLoad )
{
}
return ResourceImage::New( BROKEN_VISUAL_IMAGE_URL );
}
+void VisualFactoryCache::SetPreMultiplyOnLoad( bool preMultiply )
+{
+ mPreMultiplyOnLoad = preMultiply;
+}
+
+bool VisualFactoryCache::GetPreMultiplyOnLoad()
+{
+ return mPreMultiplyOnLoad;
+}
+
} // namespace Internal
} // namespace Toolkit
/**
* Caches shaders and geometries. Owned by VisualFactory.
*/
-class VisualFactoryCache : public RefObject
+class VisualFactoryCache
{
public:
/**
* @brief Constructor
+ *
+ * @param[in] preMultiplyOnLoad True if image visuals should pre-multiply alpha on image load.
*/
- VisualFactoryCache();
+ VisualFactoryCache( bool preMultiplyOnLoad );
+
+ /**
+ * @brief Destructor
+ */
+ ~VisualFactoryCache();
/**
* Request geometry of the given type.
*/
static Image GetBrokenVisualImage();
+ /**
+ * @copydoc Toolkit::VisualFactory::SetPreMultiplyOnLoad()
+ */
+ void SetPreMultiplyOnLoad( bool preMultiply );
+
+ /**
+ * @copydoc Toolkit::VisualFactory::GetPreMultiplyOnLoad()
+ */
+ bool GetPreMultiplyOnLoad();
+
public:
/**
* Get the image atlas manager.
protected:
/**
- * A reference counted object may only be deleted by calling Unreference()
- */
- virtual ~VisualFactoryCache();
-
- /**
* Undefined copy constructor.
*/
VisualFactoryCache(const VisualFactoryCache&);
TextureManager mTextureManager;
NPatchLoader mNPatchLoader;
SvgRasterizeThread* mSvgRasterizeThread;
+ bool mPreMultiplyOnLoad;
};
} // namespace Internal
} // namespace
VisualFactory::VisualFactory( bool debugEnabled )
-:mDebugEnabled( debugEnabled )
+: mDebugEnabled( debugEnabled ),
+ mPreMultiplyOnLoad( true )
{
}
Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& propertyMap )
{
- // Create factory cache if it hasn't already been
- if( !mFactoryCache )
- {
- mFactoryCache = new VisualFactoryCache();
- }
-
Visual::BasePtr visualPtr;
Property::Value* typeValue = propertyMap.Find( Toolkit::Visual::Property::TYPE, VISUAL_TYPE );
{
case Toolkit::Visual::BORDER:
{
- visualPtr = BorderVisual::New( *( mFactoryCache.Get() ), propertyMap );
+ visualPtr = BorderVisual::New( GetFactoryCache(), propertyMap );
break;
}
case Toolkit::Visual::COLOR:
{
- visualPtr = ColorVisual::New( *( mFactoryCache.Get() ), propertyMap );
+ visualPtr = ColorVisual::New( GetFactoryCache(), propertyMap );
break;
}
case Toolkit::Visual::GRADIENT:
{
- visualPtr = GradientVisual::New( *( mFactoryCache.Get() ), propertyMap );
+ visualPtr = GradientVisual::New( GetFactoryCache(), propertyMap );
break;
}
{
case VisualUrl::N_PATCH:
{
- visualPtr = NPatchVisual::New( *( mFactoryCache.Get() ), visualUrl, propertyMap );
+ visualPtr = NPatchVisual::New( GetFactoryCache(), visualUrl, propertyMap );
break;
}
case VisualUrl::SVG:
{
- visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), visualUrl, propertyMap );
+ visualPtr = SvgVisual::New( GetFactoryCache(), visualUrl, propertyMap );
break;
}
case VisualUrl::GIF:
{
- visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), visualUrl, propertyMap );
+ visualPtr = AnimatedImageVisual::New( GetFactoryCache(), visualUrl, propertyMap );
break;
}
case VisualUrl::REGULAR_IMAGE:
{
- visualPtr = ImageVisual::New( *( mFactoryCache.Get() ), visualUrl, propertyMap );
+ visualPtr = ImageVisual::New( GetFactoryCache(), visualUrl, propertyMap );
break;
}
}
Property::Array* array = imageURLValue->GetArray();
if( array )
{
- visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), *array, propertyMap );
+ visualPtr = AnimatedImageVisual::New( GetFactoryCache(), *array, propertyMap );
}
}
}
case Toolkit::Visual::MESH:
{
- visualPtr = MeshVisual::New( *( mFactoryCache.Get() ), propertyMap );
+ visualPtr = MeshVisual::New( GetFactoryCache(), propertyMap );
break;
}
case Toolkit::Visual::PRIMITIVE:
{
- visualPtr = PrimitiveVisual::New( *( mFactoryCache.Get() ), propertyMap );
+ visualPtr = PrimitiveVisual::New( GetFactoryCache(), propertyMap );
break;
}
case Toolkit::Visual::WIREFRAME:
{
- visualPtr = WireframeVisual::New( *( mFactoryCache.Get() ), propertyMap );
+ visualPtr = WireframeVisual::New( GetFactoryCache(), propertyMap );
break;
}
case Toolkit::Visual::TEXT:
{
- visualPtr = TextVisual::New( *( mFactoryCache.Get() ), propertyMap );
+ visualPtr = TextVisual::New( GetFactoryCache(), propertyMap );
break;
}
std::string imageUrl;
if( imageURLValue && imageURLValue->Get( imageUrl ) )
{
- visualPtr = NPatchVisual::New( *( mFactoryCache.Get() ), imageUrl, propertyMap );
+ visualPtr = NPatchVisual::New( GetFactoryCache(), imageUrl, propertyMap );
}
break;
}
std::string imageUrl;
if( imageURLValue && imageURLValue->Get( imageUrl ) )
{
- visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), imageUrl, propertyMap );
+ visualPtr = SvgVisual::New( GetFactoryCache(), imageUrl, propertyMap );
}
break;
}
{
if( imageURLValue->Get( imageUrl ) )
{
- visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), imageUrl, propertyMap );
+ visualPtr = AnimatedImageVisual::New( GetFactoryCache(), imageUrl, propertyMap );
}
else
{
Property::Array* array = imageURLValue->GetArray();
if( array )
{
- visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), *array, propertyMap );
+ visualPtr = AnimatedImageVisual::New( GetFactoryCache(), *array, propertyMap );
}
}
}
case Toolkit::DevelVisual::ANIMATED_GRADIENT:
{
- visualPtr = AnimatedGradientVisual::New( *( mFactoryCache.Get() ), propertyMap );
+ visualPtr = AnimatedGradientVisual::New( GetFactoryCache(), propertyMap );
break;
}
}
if( mDebugEnabled && visualType != Toolkit::DevelVisual::WIREFRAME )
{
//Create a WireframeVisual if we have debug enabled
- visualPtr = WireframeVisual::New( *( mFactoryCache.Get() ), visualPtr, propertyMap );
+ visualPtr = WireframeVisual::New(GetFactoryCache(), visualPtr, propertyMap );
}
return Toolkit::Visual::Base( visualPtr.Get() );
Toolkit::Visual::Base VisualFactory::CreateVisual( const Image& image )
{
- if( !mFactoryCache )
- {
- mFactoryCache = new VisualFactoryCache();
- }
-
Visual::BasePtr visualPtr;
if( image )
NinePatchImage npatchImage = NinePatchImage::DownCast( image );
if( npatchImage )
{
- visualPtr = NPatchVisual::New( *( mFactoryCache.Get() ), npatchImage );
+ visualPtr = NPatchVisual::New( GetFactoryCache(), npatchImage );
}
else
{
- visualPtr = ImageVisual::New( *( mFactoryCache.Get() ), image );
+ visualPtr = ImageVisual::New(GetFactoryCache(), image );
}
}
if( mDebugEnabled )
{
//Create a WireframeVisual if we have debug enabled
- visualPtr = WireframeVisual::New( *( mFactoryCache.Get() ), visualPtr );
+ visualPtr = WireframeVisual::New( GetFactoryCache(), visualPtr );
}
return Toolkit::Visual::Base( visualPtr.Get() );
Toolkit::Visual::Base VisualFactory::CreateVisual( const std::string& url, ImageDimensions size )
{
- if( !mFactoryCache )
- {
- mFactoryCache = new VisualFactoryCache();
- }
-
Visual::BasePtr visualPtr;
if( !url.empty() )
{
case VisualUrl::N_PATCH:
{
- visualPtr = NPatchVisual::New( *( mFactoryCache.Get() ), visualUrl );
+ visualPtr = NPatchVisual::New( GetFactoryCache(), visualUrl );
break;
}
case VisualUrl::SVG:
{
- visualPtr = SvgVisual::New( *( mFactoryCache.Get() ), visualUrl );
+ visualPtr = SvgVisual::New( GetFactoryCache(), visualUrl );
break;
}
case VisualUrl::GIF:
{
- visualPtr = AnimatedImageVisual::New( *( mFactoryCache.Get() ), visualUrl );
+ visualPtr = AnimatedImageVisual::New( GetFactoryCache(), visualUrl );
break;
}
case VisualUrl::REGULAR_IMAGE:
{
- visualPtr = ImageVisual::New( *( mFactoryCache.Get() ), visualUrl, size );
+ visualPtr = ImageVisual::New(GetFactoryCache(), visualUrl, size );
break;
}
}
if( mDebugEnabled )
{
//Create a WireframeVisual if we have debug enabled
- visualPtr = WireframeVisual::New( *( mFactoryCache.Get() ), visualPtr );
+ visualPtr = WireframeVisual::New( GetFactoryCache(), visualPtr );
}
return Toolkit::Visual::Base( visualPtr.Get() );
}
+void VisualFactory::SetPreMultiplyOnLoad( bool preMultiply )
+{
+ if( mPreMultiplyOnLoad != preMultiply )
+ {
+ GetFactoryCache().SetPreMultiplyOnLoad( preMultiply );
+ }
+ mPreMultiplyOnLoad = preMultiply;
+}
+
+bool VisualFactory::GetPreMultiplyOnLoad() const
+{
+ return mPreMultiplyOnLoad;
+}
+
Internal::TextureManager& VisualFactory::GetTextureManager()
{
+ return GetFactoryCache().GetTextureManager();
+}
+
+Internal::VisualFactoryCache& VisualFactory::GetFactoryCache()
+{
if( !mFactoryCache )
{
- mFactoryCache = new VisualFactoryCache();
+ mFactoryCache = std::unique_ptr<VisualFactoryCache>( new VisualFactoryCache( mPreMultiplyOnLoad ) );
}
- return mFactoryCache->GetTextureManager();
+ return *mFactoryCache;
}
} // namespace Internal
{
class VisualFactoryCache;
-typedef IntrusivePtr<VisualFactoryCache> VisualFactoryCachePtr;
/**
* @copydoc Toolkit::VisualFactory
VisualFactory( bool debugEnabled );
/**
- * @copydoc Toolkit::RenderFactory::CreateVisual( const Property::Map& )
+ * @copydoc Toolkit::VisualFactory::CreateVisual( const Property::Map& )
*/
Toolkit::Visual::Base CreateVisual( const Property::Map& propertyMap );
/**
- * @copydoc Toolkit::RenderFactory::CreateVisual( const Image& )
+ * @copydoc Toolkit::VisualFactory::CreateVisual( const Image& )
*/
Toolkit::Visual::Base CreateVisual( const Image& image );
/**
- * @copydoc Toolkit::RenderFactory::CreateVisual( const std::string&, ImageDimensions )
+ * @copydoc Toolkit::VisualFactory::CreateVisual( const std::string&, ImageDimensions )
*/
Toolkit::Visual::Base CreateVisual( const std::string& image, ImageDimensions size );
/**
+ * @copydoc Toolkit::VisualFactory::SetPreMultiplyOnLoad()
+ */
+ void SetPreMultiplyOnLoad( bool preMultiply );
+
+ /**
+ * @copydoc Toolkit::VisualFactory::GetPreMultiplyOnLoad()
+ */
+ bool GetPreMultiplyOnLoad() const;
+
+ /**
* @return the reference to texture manager
*/
Internal::TextureManager& GetTextureManager();
virtual ~VisualFactory();
private:
-
/**
- * Undefined copy constructor.
+ * Get the factory cache, creating it if necessary.
*/
- VisualFactory(const VisualFactory&);
+ Internal::VisualFactoryCache& GetFactoryCache();
- /**
- * Undefined assignment operator.
- */
- VisualFactory& operator=(const VisualFactory& rhs);
+ VisualFactory(const VisualFactory&) = delete;
-private:
+ VisualFactory& operator=(const VisualFactory& rhs) = delete;
- VisualFactoryCachePtr mFactoryCache;
- bool mDebugEnabled;
+private:
+ std::unique_ptr<VisualFactoryCache> mFactoryCache;
+ bool mDebugEnabled:1;
+ bool mPreMultiplyOnLoad:1; ///< Local store for this flag
};
/**
const char * const MIX_COLOR( "mixColor" );
const char * const OPACITY( "opacity" );
+// Color visual
+const char * const RENDER_IF_TRANSPARENT_NAME( "renderIfTransparent" );
+
// Image visual
const char * const IMAGE_URL_NAME( "url" );
const char * const ATLAS_RECT_UNIFORM_NAME( "uAtlasRect" );
extern const char * const MIX_COLOR;
extern const char * const OPACITY;
+// Color visual
+extern const char * const RENDER_IF_TRANSPARENT_NAME;
+
// Image visual
extern const char * const IMAGE_URL_NAME;
extern const char * const ATLAS_RECT_UNIFORM_NAME;
return mLocation == VisualUrl::LOCAL;
}
-std::string VisualUrl::GetLocation()
+std::string VisualUrl::GetLocation() const
{
const auto location = mUrl.find( "://" );
if( std::string::npos != location )
/**
* @return the location part of the url
*/
- std::string GetLocation();
+ std::string GetLocation() const;
/**
* Helper to create a URL of type TEXTURE
#include <dali/integration-api/debug.h>
// INTERNAL INCLUDES
-#include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
+#include <dali-toolkit/public-api/align-enumerations.h>
#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
#include <dali-toolkit/public-api/styling/style-manager.h>
#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
#include <dali-toolkit/devel-api/controls/control-devel.h>
-#include <dali-toolkit/public-api/visuals/visual-properties.h>
#include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
+#include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
#include <dali-toolkit/internal/styling/style-manager-impl.h>
#include <dali-toolkit/internal/visuals/color/color-visual.h>
#include <dali-toolkit/internal/visuals/visual-string-constants.h>
-#include <dali-toolkit/public-api/align-enumerations.h>
#include <dali-toolkit/internal/controls/control/control-data-impl.h>
namespace Dali
#endif
/**
+ * @brief Replace the background visual if it's a color visual with the renderIfTransparent property set as required.
+ * @param[in] controlImpl The control implementation
+ * @param[in] renderIfTransaparent Whether we should render if the color is transparent
+ */
+void ChangeBackgroundColorVisual( Control& controlImpl, bool renderIfTransparent )
+{
+ Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
+
+ Toolkit::Visual::Base backgroundVisual = controlDataImpl.GetVisual( Toolkit::Control::Property::BACKGROUND );
+ if( backgroundVisual )
+ {
+ Property::Map map;
+ backgroundVisual.CreatePropertyMap( map );
+ Property::Value* typeValue = map.Find( Toolkit::Visual::Property::TYPE );
+ if( typeValue && typeValue->Get< int >() == Toolkit::Visual::COLOR )
+ {
+ // Only change it if it's a color visual
+ map[ Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT ] = renderIfTransparent;
+ controlImpl.SetBackground( map );
+ }
+ }
+}
+
+/**
* @brief Creates a clipping renderer if required.
* (EG. If no renders exist and clipping is enabled).
* @param[in] controlImpl The control implementation.
int clippingMode = ClippingMode::DISABLED;
if( self.GetProperty( Actor::Property::CLIPPING_MODE ).Get( clippingMode ) )
{
- Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
-
- if( ( clippingMode == ClippingMode::CLIP_CHILDREN ) &&
- controlDataImpl.mVisuals.Empty() &&
- ( self.GetRendererCount() == 0u ) )
+ switch( clippingMode )
{
- controlImpl.SetBackgroundColor( Color::TRANSPARENT );
+ case ClippingMode::CLIP_CHILDREN:
+ {
+ if( self.GetRendererCount() == 0u )
+ {
+ Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
+ if( controlDataImpl.mVisuals.Empty() )
+ {
+ controlImpl.SetBackgroundColor( Color::TRANSPARENT );
+ }
+ else
+ {
+ // We have visuals, check if we've set the background and re-create it to
+ // render even if transparent (only if it's a color visual)
+ ChangeBackgroundColorVisual( controlImpl, true );
+ }
+ }
+ break;
+ }
+
+ case ClippingMode::DISABLED:
+ case ClippingMode::CLIP_TO_BOUNDING_BOX:
+ {
+ // If we have a background visual, check if it's a color visual and remove the render if transparent flag
+ ChangeBackgroundColorVisual( controlImpl, false );
+ break;
+ }
}
}
}
map[ Toolkit::Visual::Property::TYPE ] = Toolkit::Visual::COLOR;
map[ Toolkit::ColorVisual::Property::MIX_COLOR ] = color;
+ int clippingMode = ClippingMode::DISABLED;
+ if( ( Self().GetProperty( Actor::Property::CLIPPING_MODE ).Get( clippingMode ) ) &&
+ ( clippingMode == ClippingMode::CLIP_CHILDREN ) )
+ {
+ // If clipping-mode is set to CLIP_CHILDREN, then force visual to add the render even if transparent
+ map[ Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT ] = true;
+ }
+
SetBackground( map );
}
const unsigned int TOOLKIT_MAJOR_VERSION = 1;
const unsigned int TOOLKIT_MINOR_VERSION = 3;
-const unsigned int TOOLKIT_MICRO_VERSION = 5;
+const unsigned int TOOLKIT_MICRO_VERSION = 6;
const char * const TOOLKIT_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
Name: dali-toolkit
Summary: Dali 3D engine Toolkit
-Version: 1.3.5
+Version: 1.3.6
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT