#include <dali/devel-api/scripting/scripting.h>
#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
#include <dali/public-api/rendering/renderer.h>
#include <test-native-image.h>
END_TEST;
}
-
int UtcDaliImageViewSyncLoading02(void)
{
ToolkitTestApplication application;
END_TEST;
}
+int UtcDaliImageViewAddedTexture(void)
+{
+ ToolkitTestApplication application;
+
+ tet_infoline("ImageView Testing image view with texture provided manager url");
+
+ ImageView imageView = ImageView::New();
+
+ // empty texture is ok, though pointless from app point of view
+ TextureSet empty;
+ std::string url = TextureManager::AddTexture(empty);
+ DALI_TEST_CHECK(url.size() > 0u);
+
+ Property::Map propertyMap;
+ propertyMap[ImageVisual::Property::URL] = url;
+ imageView.SetProperty(ImageView::Property::IMAGE, propertyMap);
+
+ Stage::GetCurrent().Add( imageView );
+ application.SendNotification();
+ application.Render();
+
+ END_TEST;
+}
+
int UtcDaliImageViewSizeWithBackground(void)
{
ToolkitTestApplication application;
const char* const PROPERTY_NAME_PIXEL_SIZE = "pixelSize";
const char* const PROPERTY_NAME_ENABLE_SELECTION = "enableSelection";
const char* const PROPERTY_NAME_PLACEHOLDER = "placeholder";
+const char* const PROPERTY_NAME_ELLIPSIS = "ellipsis";
const int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_PIXEL_SIZE ) == DevelTextField::Property::PIXEL_SIZE );
DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_ENABLE_SELECTION ) == DevelTextField::Property::ENABLE_SELECTION );
DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_PLACEHOLDER ) == DevelTextField::Property::PLACEHOLDER );
+ DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_ELLIPSIS ) == DevelTextField::Property::ELLIPSIS );
END_TEST;
}
placeholderPixelSizeMapSet["placeholderColor"] = Color::BLUE;
placeholderPixelSizeMapSet["placeholderFontFamily"] = "Arial";
placeholderPixelSizeMapSet["placeholderPixelSize"] = 15.0f;
+ placeholderPixelSizeMapSet["placeholderEllipsis"] = true;
placeholderFontstyleMap.Insert( "weight", "bold" );
placeholderPixelSizeMapSet["placeholderFontStyle"] = placeholderFontstyleMap;
placeholderMapSet["placeholderColor"] = Color::RED;
placeholderMapSet["placeholderFontFamily"] = "Arial";
placeholderMapSet["placeholderPointSize"] = 12.0f;
+ placeholderMapSet["placeholderEllipsis"] = false;
// Check the placeholder font style property
placeholderFontstyleMap.Clear();
DALI_TEST_EQUALS( placeholderMapGet.Count(), placeholderMapSet.Count(), TEST_LOCATION );
DALI_TEST_EQUALS( DaliTestCheckMaps( placeholderMapGet, placeholderMapSet ), true, TEST_LOCATION );
+ // Check the ellipsis property
+ DALI_TEST_CHECK( !field.GetProperty<bool>( DevelTextField::Property::ELLIPSIS ) );
+ field.SetProperty( DevelTextField::Property::ELLIPSIS, true );
+ DALI_TEST_CHECK( field.GetProperty<bool>( DevelTextField::Property::ELLIPSIS ) );
+
END_TEST;
}
TextLabel label = TextLabel::New();
DALI_TEST_CHECK( label );
+ Stage::GetCurrent().Add( label );
+
// Note - we can't check the defaults since the stylesheets are platform-specific
label.SetProperty( TextLabel::Property::RENDERING_BACKEND, Text::RENDERING_SHARED_ATLAS );
DALI_TEST_EQUALS( (Text::RenderingType)label.GetProperty<int>( TextLabel::Property::RENDERING_BACKEND ), Text::RENDERING_SHARED_ATLAS, TEST_LOCATION );
label.SetProperty( TextLabel::Property::ENABLE_MARKUP, true );
DALI_TEST_CHECK( label.GetProperty<bool>( TextLabel::Property::ENABLE_MARKUP ) );
+ // Check the text property when markup is enabled
+ label.SetProperty( TextLabel::Property::TEXT, "<color value='white'>Markup</color><color value='cyan'>Text</color>" );
+ DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::TEXT ), std::string("MarkupText"), TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render();
+
// Check autoscroll properties
const int SCROLL_SPEED = 80;
const int SCROLL_LOOPS = 4;
label.SetProperty( TextLabel::Property::UNDERLINE, underlineMapSet );
+ application.SendNotification();
+ application.Render();
+
underlineMapGet = label.GetProperty<Property::Map>( TextLabel::Property::UNDERLINE );
DALI_TEST_EQUALS( underlineMapGet.Count(), underlineMapSet.Count(), TEST_LOCATION );
DALI_TEST_EQUALS( DaliTestCheckMaps( underlineMapGet, underlineMapSet ), true, TEST_LOCATION );
label.SetProperty( TextLabel::Property::ENABLE_MARKUP, true );
label.SetProperty( TextLabel::Property::TEXT, emojis );
+ Property::Map shadowMap;
+ shadowMap.Insert( "color", "green" );
+ shadowMap.Insert( "offset", "2 2" );
+ label.SetProperty( TextLabel::Property::SHADOW, shadowMap );
+
application.SendNotification();
application.Render();
* propertyMap["placeholderColor"] = Color::RED;
* propertyMap["placeholderFontFamily"] = "Arial";
* propertyMap["placeholderPointSize"] = 12.0f;
+ * propertyMap["placeholderEllipsis"] = true;
*
* Property::Map fontStyleMap;
* fontStyleMap.Insert( "weight", "bold" );
*
* @details name "placeholder", type MAP
*/
- PLACEHOLDER = INPUT_OUTLINE + 4
+ PLACEHOLDER = INPUT_OUTLINE + 4,
+
+ /**
+ * @brief Enable or disable the ellipsis.
+ * @details name "ellipsis", type Property::BOOLEAN.
+ * @note PLACEHOLDER map is used to add ellipsis to placeholder text.
+ */
+ ELLIPSIS = INPUT_OUTLINE + 5
};
} // namespace Property
devel_api_image_loader_header_files = \
$(devel_api_src_dir)/image-loader/async-image-loader-devel.h \
$(devel_api_src_dir)/image-loader/atlas-upload-observer.h \
- $(devel_api_src_dir)/image-loader/image-atlas.h
+ $(devel_api_src_dir)/image-loader/image-atlas.h \
+ $(devel_api_src_dir)/image-loader/texture-manager.h
devel_api_scripting_header_files = \
$(devel_api_src_dir)/scripting/script.h \
DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextField, "pixelSize", FLOAT, PIXEL_SIZE )
DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextField, "enableSelection", BOOLEAN, ENABLE_SELECTION )
DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextField, "placeholder", MAP, PLACEHOLDER )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextField, "ellipsis", BOOLEAN, ELLIPSIS )
DALI_SIGNAL_REGISTRATION( Toolkit, TextField, "textChanged", SIGNAL_TEXT_CHANGED )
DALI_SIGNAL_REGISTRATION( Toolkit, TextField, "maxLengthReached", SIGNAL_MAX_LENGTH_REACHED )
}
break;
}
+ case Toolkit::DevelTextField::Property::ELLIPSIS:
+ {
+ if( impl.mController )
+ {
+ const bool ellipsis = value.Get<bool>();
+ DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p ELLIPSIS %d\n", impl.mController.Get(), ellipsis );
+
+ impl.mController->SetTextElideEnabled( ellipsis );
+ }
+ break;
+ }
} // switch
} // textfield
}
value = map;
break;
}
+ case Toolkit::DevelTextField::Property::ELLIPSIS:
+ {
+ if( impl.mController )
+ {
+ value = impl.mController->IsTextElideEnabled();
+ }
+ break;
+ }
} //switch
}
}
else
{
+ // Whether the given glyph is a color one.
+ const bool isColorGlyph = Pixel::BGRA8888 == data.glyphBitmap.format;
+
// Initial vertical offset.
const int yOffset = data.verticalOffset + position->y;
uint8_t* bitmapBuffer = reinterpret_cast< uint8_t* >( data.bitmapBuffer.GetBuffer() );
- // Update the alpha channel.
- const uint8_t alpha = *( data.glyphBitmap.buffer + glyphBufferOffset + index );
-
- // Copy non-transparent pixels only
- if ( alpha > 0u )
+ if ( !isColorGlyph )
{
- // Check alpha of overlapped pixels
- uint8_t& currentAlpha = *( bitmapBuffer + verticalOffset + xOffsetIndex );
- uint8_t newAlpha = static_cast<uint8_t>( color->a * static_cast<float>( alpha ) );
-
- // For any pixel overlapped with the pixel in previous glyphs, make sure we don't
- // overwrite a previous bigger alpha with a smaller alpha (in order to avoid
- // semi-transparent gaps between joint glyphs with overlapped pixels, which could
- // happen, for example, in the RTL text when we copy glyphs from right to left).
- *( bitmapBuffer + verticalOffset + xOffsetIndex ) = std::max( currentAlpha, newAlpha );
+ // Update the alpha channel.
+ const uint8_t alpha = *( data.glyphBitmap.buffer + glyphBufferOffset + index );
+
+ // Copy non-transparent pixels only
+ if ( alpha > 0u )
+ {
+ // Check alpha of overlapped pixels
+ uint8_t& currentAlpha = *( bitmapBuffer + verticalOffset + xOffsetIndex );
+ uint8_t newAlpha = static_cast<uint8_t>( color->a * static_cast<float>( alpha ) );
+
+ // For any pixel overlapped with the pixel in previous glyphs, make sure we don't
+ // overwrite a previous bigger alpha with a smaller alpha (in order to avoid
+ // semi-transparent gaps between joint glyphs with overlapped pixels, which could
+ // happen, for example, in the RTL text when we copy glyphs from right to left).
+ *( bitmapBuffer + verticalOffset + xOffsetIndex ) = std::max( currentAlpha, newAlpha );
+ }
}
}
}
mAllTextSelected( false ),
mUpdateInputStyle( false ),
mPasswordInput( false ),
- mIsPlaceholderPixelSize( false )
+ mIsPlaceholderPixelSize( false ),
+ mIsPlaceholderElideEnabled( false ),
+ mPlaceholderEllipsisFlag( false )
{
mImfManager = ImfManager::Get();
}
bool mPasswordInput : 1; ///< True if password input is enabled.
bool mCheckScrollAmount : 1; ///< Whether to check scrolled amount after updating the position
bool mIsPlaceholderPixelSize : 1; ///< True if the placeholder font size is set as pixel size.
+ bool mIsPlaceholderElideEnabled : 1; ///< True if the placeholder text's elide is enabled.
+ bool mPlaceholderEllipsisFlag : 1; ///< True if the text controller sets the placeholder ellipsis.
};
struct ModifyEvent
const char * const PLACEHOLDER_FONT_STYLE = "placeholderFontStyle";
const char * const PLACEHOLDER_POINT_SIZE = "placeholderPointSize";
const char * const PLACEHOLDER_PIXEL_SIZE = "placeholderPixelSize";
+const char * const PLACEHOLDER_ELLIPSIS = "placeholderEllipsis";
float ConvertToEven( float value )
{
return mImpl->mModel->mElideEnabled;
}
+void Controller::SetPlaceholderTextElideEnabled( bool enabled )
+{
+ mImpl->mEventData->mIsPlaceholderElideEnabled = enabled;
+ mImpl->mEventData->mPlaceholderEllipsisFlag = true;
+
+ // Update placeholder if there is no text
+ if( mImpl->IsShowingPlaceholderText() ||
+ ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
+ {
+ ShowPlaceholderText();
+ }
+}
+
+bool Controller::IsPlaceholderTextElideEnabled() const
+{
+ return mImpl->mEventData->mIsPlaceholderElideEnabled;
+}
+
void Controller::SetSelectionEnabled( bool enabled )
{
mImpl->mEventData->mSelectionEnabled = enabled;
SetPlaceholderTextFontSize( pixelSize, Text::Controller::PIXEL_SIZE );
}
}
+ else if( key == PLACEHOLDER_ELLIPSIS )
+ {
+ bool ellipsis;
+ value.Get( ellipsis );
+ SetPlaceholderTextElideEnabled( ellipsis );
+ }
}
}
{
map[ PLACEHOLDER_PIXEL_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE );
}
+
+ if( mImpl->mEventData->mPlaceholderEllipsisFlag )
+ {
+ map[ PLACEHOLDER_ELLIPSIS ] = IsPlaceholderTextElideEnabled();
+ }
}
}
COLOR );
}
+ // Set the update info to elide the text.
+ if( mImpl->mModel->mElideEnabled ||
+ ( ( NULL != mImpl->mEventData ) && mImpl->mEventData->mIsPlaceholderElideEnabled ) )
+ {
+ // Update Text layout for applying elided
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+ ALIGN |
+ LAYOUT |
+ UPDATE_LAYOUT_SIZE |
+ REORDER );
+ mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
+ mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
+ }
+
// Make sure the model is up-to-date before layouting.
ProcessModifyEvents();
bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
+ // Update the ellipsis
+ bool elideTextEnabled = mImpl->mModel->mElideEnabled;
+
+ if( NULL != mImpl->mEventData )
+ {
+ if( mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText() )
+ {
+ elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled;
+ }
+ else if( EventData::INACTIVE != mImpl->mEventData->mState )
+ {
+ // Disable ellipsis when editing
+ elideTextEnabled = false;
+ }
+
+ // Reset the scroll position in inactive state
+ if( elideTextEnabled && ( mImpl->mEventData->mState == EventData::INACTIVE ) )
+ {
+ ResetScrollPosition();
+ }
+ }
+
// Update the visual model.
Size newLayoutSize;
viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
glyphPositions,
mImpl->mModel->mVisualModel->mLines,
newLayoutSize,
- mImpl->mModel->mElideEnabled );
+ elideTextEnabled );
viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
bool IsTextElideEnabled() const;
/**
+ * @brief Enable or disable the placeholder text elide.
+ * @param enabled Whether to enable the placeholder text elide.
+ */
+ void SetPlaceholderTextElideEnabled( bool enabled );
+
+ /**
+ * @brief Whether the placeholder text elide property is enabled.
+ * @return True if the placeholder text elide property is enabled, false otherwise.
+ */
+ bool IsPlaceholderTextElideEnabled() const;
+
+ /**
* @brief Enable or disable the text selection.
* @param[in] enabled Whether to enable the text selection.
*/
{
mWrapModeU = Dali::WrapMode::Type::DEFAULT;
}
+ break;
}
case Toolkit::ImageVisual::Property::WRAP_MODE_V:
{
Dali::SamplingMode::Type samplingMode )
: Visual::Base( factoryCache ),
mImage(),
- mPixels(),
mPixelArea( FULL_TEXTURE_RECT ),
mPlacementActor(),
mImageUrl( imageUrl ),
- mMaskingData( NULL ),
+ mMaskingData( ),
mDesiredSize( size ),
mTextureId( TextureManager::INVALID_TEXTURE_ID ),
mFittingMode( fittingMode ),
mWrapModeU( WrapMode::DEFAULT ),
mWrapModeV( WrapMode::DEFAULT ),
mAttemptAtlasing( false ),
- mTextureLoading( false )
+ mLoadingStatus( false )
{
}
ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, const Image& image )
: Visual::Base( factoryCache ),
mImage( image ),
- mPixels(),
mPixelArea( FULL_TEXTURE_RECT ),
mPlacementActor(),
mImageUrl(),
- mMaskingData( NULL ),
+ mMaskingData( ),
mDesiredSize(),
mTextureId( TextureManager::INVALID_TEXTURE_ID ),
mFittingMode( FittingMode::DEFAULT ),
mWrapModeU( WrapMode::DEFAULT ),
mWrapModeV( WrapMode::DEFAULT ),
mAttemptAtlasing( false ),
- mTextureLoading( false )
+ mLoadingStatus( false )
{
}
ImageVisual::~ImageVisual()
{
- delete mMaskingData;
+ if( mMaskingData && Stage::IsInstalled() )
+ {
+ // TextureManager could have been deleted before the actor that contains this
+ // ImageVisual is destroyed (e.g. due to stage shutdown). Ensure the stage
+ // is still valid before accessing texture manager.
+ if( mMaskingData->mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID )
+ {
+ TextureManager& textureManager = mFactoryCache.GetTextureManager();
+ textureManager.Remove( mMaskingData->mAlphaMaskId );
+ }
+ }
}
void ImageVisual::DoSetProperties( const Property::Map& propertyMap )
}
}
}
-
- if( ( mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING ) && mImageUrl.IsValid() )
- {
- // if sync loading is required, the loading should start
- // immediately when new image url is set or the actor is off stage
- // ( for on-stage actor with image url unchanged, resource loading
- // is already finished )
- LoadResourceSynchronously();
- }
}
void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& value )
{
AllocateMaskData();
// Immediately trigger the alpha mask loading (it may just get a cached value)
- mMaskingData->SetImage( alphaUrl );
+ mMaskingData->mAlphaMaskUrl = alphaUrl;
+ TextureManager& textureManager = mFactoryCache.GetTextureManager();
+ mMaskingData->mAlphaMaskId = textureManager.RequestMaskLoad( alphaUrl );
}
break;
}
void ImageVisual::AllocateMaskData()
{
- if( mMaskingData == NULL )
+ if( !mMaskingData )
{
- TextureManager& textureManager = mFactoryCache.GetTextureManager();
- mMaskingData = new MaskingData(textureManager);
+ mMaskingData.reset(new TextureManager::MaskingData());
}
}
return mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
}
-void ImageVisual::LoadResourceSynchronously()
-{
- if( mImageUrl.IsValid() )
- {
- Devel::PixelBuffer pixelBuffer = LoadImageFromFile( mImageUrl.GetUrl(), mDesiredSize, mFittingMode, mSamplingMode );
-
- if( pixelBuffer )
- {
- mPixels = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
- }
- mTextureLoading = false;
- }
-}
-
-TextureSet ImageVisual::CreateTextureSet( Vector4& textureRect, bool synchronousLoading, bool attemptAtlasing )
-{
- TextureSet textureSet;
-
- mTextureLoading = false;
-
- textureRect = FULL_TEXTURE_RECT;
- if( synchronousLoading )
- {
- if( !mPixels )
- {
- // use broken image
- textureSet = TextureSet::New();
- TextureSetImage( textureSet, 0u, VisualFactoryCache::GetBrokenVisualImage() );
- }
- else
- {
- if( attemptAtlasing )
- {
- textureSet = mFactoryCache.GetAtlasManager()->Add(textureRect, mPixels );
- mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
- }
- if( !textureSet ) // big image, no atlasing or atlasing failed
- {
- mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
- Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, mPixels.GetPixelFormat(),
- mPixels.GetWidth(), mPixels.GetHeight() );
- texture.Upload( mPixels );
- textureSet = TextureSet::New();
- textureSet.SetTexture( 0u, texture );
- }
- }
- }
- else
- {
- if( attemptAtlasing )
- {
- textureSet = mFactoryCache.GetAtlasManager()->Add( textureRect, mImageUrl.GetUrl(), mDesiredSize, mFittingMode, true, this );
- mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
- mTextureLoading = true;
- }
- if( !textureSet ) // big image, no atlasing or atlasing failed
- {
- mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
- TextureManager& textureManager = mFactoryCache.GetTextureManager();
- if( mMaskingData == NULL )
- {
- mTextureId = textureManager.RequestLoad( mImageUrl, mDesiredSize, mFittingMode,
- mSamplingMode, TextureManager::NO_ATLAS, this );
- }
- else
- {
- mTextureId = textureManager.RequestLoad( mImageUrl,
- mMaskingData->mAlphaMaskId,
- mMaskingData->mContentScaleFactor,
- mDesiredSize,
- mFittingMode, mSamplingMode,
- TextureManager::NO_ATLAS,
- mMaskingData->mCropToMask,
- this );
- }
-
- TextureManager::LoadState loadState = textureManager.GetTextureState( mTextureId );
-
- mTextureLoading = ( loadState == TextureManager::LOADING );
-
- if( loadState == TextureManager::UPLOADED )
- {
- // UploadComplete has already been called - keep the same texture set
- textureSet = textureManager.GetTextureSet(mTextureId);
- }
- }
- }
-
- if( ! (mImpl->mFlags & Impl::IS_ATLASING_APPLIED) && textureSet )
- {
- Sampler sampler = Sampler::New();
- sampler.SetWrapMode( mWrapModeU, mWrapModeV );
- textureSet.SetSampler( 0u, sampler );
- }
-
- return textureSet;
-}
-
+/*
+( VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode,
+ ImageVisual::MaskingData* maskInfo, bool synchronousLoading,
+ TextureManager::TextureId textureId, Vector4& textureRect, bool& atlasingStatus, bool& loadingStatus
+ */
void ImageVisual::InitializeRenderer()
{
mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
+ TextureManager& textureManager = mFactoryCache.GetTextureManager();
+
if( ! mImpl->mCustomShader && mImageUrl.GetProtocolType() == VisualUrl::LOCAL )
{
bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
Vector4 atlasRect;
+
+ auto attemptAtlasing = mAttemptAtlasing;
+
// texture set has to be created first as we need to know if atlasing succeeded or not
// when selecting the shader
- TextureSet textures = CreateTextureSet( atlasRect, IsSynchronousResourceLoading(), mAttemptAtlasing );
+ TextureSet textures =
+ textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode,
+ mMaskingData, IsSynchronousResourceLoading(), mTextureId,
+ atlasRect, attemptAtlasing, mLoadingStatus, mWrapModeU,
+ mWrapModeV, this, this, mFactoryCache.GetAtlasManager());
+ if(attemptAtlasing)
+ {
+ mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
+ }
CreateRenderer( textures );
if( mImpl->mFlags & Impl::IS_ATLASING_APPLIED ) // the texture is packed inside atlas
{
mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect );
- if( !defaultWrapMode ) // custom wrap mode, renderer is not cached.
+ if( !defaultWrapMode ) // custom wrap mode
{
Vector2 wrapMode(mWrapModeU-WrapMode::CLAMP_TO_EDGE, mWrapModeV-WrapMode::CLAMP_TO_EDGE);
wrapMode.Clamp( Vector2::ZERO, Vector2( 2.f, 2.f ) );
}
else
{
+ auto attemptAtlasing = false;
// for custom shader or remote image, atlas is not applied
Vector4 atlasRect; // ignored in this case
- TextureSet textures = CreateTextureSet( atlasRect, IsSynchronousResourceLoading(), false );
+ TextureSet textures =
+ textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode,
+ mMaskingData, IsSynchronousResourceLoading(), mTextureId,
+ atlasRect, attemptAtlasing, mLoadingStatus, mWrapModeU, mWrapModeV, this,
+ nullptr, nullptr); // no atlasing
+ DALI_ASSERT_DEBUG(attemptAtlasing == false);
CreateRenderer( textures );
}
}
void ImageVisual::InitializeRenderer( const Image& image )
{
- // don't reuse CreateTextureSet
TextureSet textures = TextureSet::New();
NativeImage nativeImage = NativeImage::DownCast( image );
mImpl->mRenderer.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, mPixelArea );
}
- if( mTextureLoading == false )
+ if( mLoadingStatus == false )
{
actor.AddRenderer( mImpl->mRenderer );
mPlacementActor.Reset();
RemoveTexture( mImageUrl.GetUrl() );
mImage.Reset();
}
- mTextureLoading = false;
+ mLoadingStatus = false;
mImpl->mRenderer.Reset();
mPlacementActor.Reset();
}
// reset the weak handle so that the renderer only get added to actor once
mPlacementActor.Reset();
}
- mTextureLoading = false;
+ mLoadingStatus = false;
}
// From Texture Manager
ResourceReady();
}
}
- mTextureLoading = false;
+ mLoadingStatus = false;
}
void ImageVisual::RemoveTexture(const std::string& url)
}
}
-
-ImageVisual::MaskingData::MaskingData( TextureManager& textureManager )
-: mTextureManager( textureManager ),
- mAlphaMaskUrl(),
- mAlphaMaskId( TextureManager::INVALID_TEXTURE_ID ),
- mContentScaleFactor( 1.0f ),
- mCropToMask( true )
-{
-}
-
-ImageVisual::MaskingData::~MaskingData()
-{
- if( Stage::IsInstalled() )
- {
- // TextureManager could have been deleted before the actor that contains this
- // ImageVisual is destroyed (e.g. due to stage shutdown). Ensure the stage
- // is still valid before accessing texture manager.
- if( mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID )
- {
- mTextureManager.Remove( mAlphaMaskId );
- }
- }
-}
-
-void ImageVisual::MaskingData::SetImage( const std::string& maskUrl )
-{
- mAlphaMaskUrl = maskUrl;
- mAlphaMaskId = mTextureManager.RequestMaskLoad( mAlphaMaskUrl );
-}
-
} // namespace Internal
} // namespace Toolkit
*/
// EXTERNAL INCLUDES
+#include <memory>
+
#include <dali/public-api/common/intrusive-ptr.h>
#include <dali/public-api/images/image.h>
#include <dali/public-api/images/image-operations.h>
bool IsSynchronousResourceLoading() const;
/**
- * @brief Load the resource synchronously
- */
- void LoadResourceSynchronously();
-
- /**
* Creates the texture set and adds the texture to it
* @param[out] textureRect The texture area of the texture in the atlas.
* @param[in] url The URL of the image resource to use.
void DoSetProperty( Property::Index index, const Property::Value& value );
private:
- struct MaskingData
- {
- MaskingData( TextureManager& textureManager );
- ~MaskingData();
- void SetImage( const std::string& url );
-
- TextureManager& mTextureManager;
- VisualUrl mAlphaMaskUrl;
- TextureManager::TextureId mAlphaMaskId;
- float mContentScaleFactor;
- bool mCropToMask;
- };
Image mImage;
- PixelData mPixels;
Vector4 mPixelArea;
WeakHandle<Actor> mPlacementActor;
VisualUrl mImageUrl;
- MaskingData* mMaskingData;
+ TextureManager::MaskingDataPointer mMaskingData;
Dali::ImageDimensions mDesiredSize;
TextureManager::TextureId mTextureId;
Dali::SamplingMode::Type mSamplingMode:4;
Dali::WrapMode::Type mWrapModeU:3;
Dali::WrapMode::Type mWrapModeV:3;
- bool mAttemptAtlasing:1; ///< If true will attempt atlasing, otherwise create unique texture
- bool mTextureLoading:1; ///< True if the texture is being loaded asynchronously, or false when it has loaded.
+ bool mAttemptAtlasing; ///< If true will attempt atlasing, otherwise create unique texture
+ bool mLoadingStatus; ///< True if the texture is being loaded asynchronously, or false when it has loaded.
};
}\n
);
-const char* FRAGMENT_SHADER_ATLAS_CLAMP_RGBA = DALI_COMPOSE_SHADER(
+const char* FRAGMENT_SHADER_SINGLE_COLOR_TEXT = DALI_COMPOSE_SHADER(
+ varying mediump vec2 vTexCoord;\n
+ uniform sampler2D sTexture;\n
+ uniform lowp vec4 uTextColorAnimatable;\n
+ uniform mediump vec4 uAtlasRect;\n
+ uniform lowp vec4 uColor;\n
+ uniform lowp vec3 mixColor;\n
+ uniform lowp float opacity;\n
+ \n
+ void main()\n
+ {\n
+ mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );\n
+ mediump float textTexture = texture2D( sTexture, texCoord ).r;\n
+
+ // Set the color of the text to what it is animated to.
+ gl_FragColor = uTextColorAnimatable * textTexture * uColor * vec4( mixColor, opacity );
+ }\n
+);
+
+const char* FRAGMENT_SHADER_MULTI_COLOR_TEXT = DALI_COMPOSE_SHADER(
+ varying mediump vec2 vTexCoord;\n
+ uniform sampler2D sTexture;\n
+ uniform mediump vec4 uAtlasRect;\n
+ uniform lowp vec4 uColor;\n
+ uniform lowp vec3 mixColor;\n
+ uniform lowp float opacity;\n
+ \n
+ void main()\n
+ {\n
+ mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );\n
+ mediump vec4 textTexture = texture2D( sTexture, texCoord );\n
+
+ gl_FragColor = textTexture * uColor * vec4( mixColor, opacity );
+ }\n
+);
+
+const char* FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE = DALI_COMPOSE_SHADER(
varying mediump vec2 vTexCoord;\n
uniform sampler2D sTexture;\n
uniform sampler2D sStyle;\n
- uniform sampler2D sMask;\n
- uniform lowp float uHasMultipleTextColors;\n
uniform lowp vec4 uTextColorAnimatable;\n
uniform mediump vec4 uAtlasRect;\n
uniform lowp vec4 uColor;\n
void main()\n
{\n
mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );\n
+ mediump float textTexture = texture2D( sTexture, texCoord ).r;\n
+ mediump vec4 styleTexture = texture2D( sStyle, texCoord );\n
+
+ // Draw the text as overlay above the style
+ gl_FragColor = ( uTextColorAnimatable * textTexture + styleTexture * ( 1.0 - textTexture ) ) * uColor * vec4( mixColor, opacity );\n
+ }\n
+);
+
+const char* FRAGMENT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE = DALI_COMPOSE_SHADER(
+ varying mediump vec2 vTexCoord;\n
+ uniform sampler2D sTexture;\n
+ uniform sampler2D sStyle;\n
+ uniform mediump vec4 uAtlasRect;\n
+ uniform lowp vec4 uColor;\n
+ uniform lowp vec3 mixColor;\n
+ uniform lowp float opacity;\n
+ \n
+ void main()\n
+ {\n
+ mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );\n
mediump vec4 textTexture = texture2D( sTexture, texCoord );\n
mediump vec4 styleTexture = texture2D( sStyle, texCoord );\n
- mediump vec4 maskTexture = texture2D( sMask, texCoord );\n
+
+ // Draw the text as overlay above the style
+ gl_FragColor = ( textTexture + styleTexture * ( 1.0 - textTexture.a ) ) * uColor * vec4( mixColor, opacity );\n
+ }\n
+);
+
+const char* FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI = DALI_COMPOSE_SHADER(
+ varying mediump vec2 vTexCoord;\n
+ uniform sampler2D sTexture;\n
+ uniform sampler2D sMask;\n
+ uniform lowp vec4 uTextColorAnimatable;\n
+ uniform mediump vec4 uAtlasRect;\n
+ uniform lowp vec4 uColor;\n
+ uniform lowp vec3 mixColor;\n
+ uniform lowp float opacity;\n
+ \n
+ void main()\n
+ {\n
+ mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );\n
+ mediump vec4 textTexture = texture2D( sTexture, texCoord );\n
+ mediump float maskTexture = texture2D( sMask, texCoord ).r;\n
// Set the color of non-transparent pixel in text to what it is animated to.
// Markup text with multiple text colors are not animated (but can be supported later on if required).
// Emoji color are not animated.
mediump vec4 textColor = textTexture * textTexture.a;\n
mediump float vstep = step( 0.0001, textColor.a );\n
- textColor.rgb = mix( textColor.rgb, uTextColorAnimatable.rgb, vstep * maskTexture.a * ( 1.0 - uHasMultipleTextColors ) );\n
+ textColor.rgb = mix( textColor.rgb, uTextColorAnimatable.rgb, vstep * maskTexture );\n
// Draw the text as overlay above the style
- gl_FragColor = ( textColor + styleTexture * ( 1.0 - textTexture.a ) ) * uColor * vec4( mixColor, opacity );\n
+ gl_FragColor = textColor * uColor * vec4( mixColor, opacity );\n
}\n
);
-const char* FRAGMENT_SHADER_ATLAS_CLAMP_L8 = DALI_COMPOSE_SHADER(
+const char* FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI = DALI_COMPOSE_SHADER(
varying mediump vec2 vTexCoord;\n
uniform sampler2D sTexture;\n
+ uniform sampler2D sStyle;\n
+ uniform sampler2D sMask;\n
+ uniform lowp float uHasMultipleTextColors;\n
uniform lowp vec4 uTextColorAnimatable;\n
uniform mediump vec4 uAtlasRect;\n
uniform lowp vec4 uColor;\n
void main()\n
{\n
mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );\n
- mediump float textTexture = texture2D( sTexture, texCoord ).r;\n
+ mediump vec4 textTexture = texture2D( sTexture, texCoord );\n
+ mediump vec4 styleTexture = texture2D( sStyle, texCoord );\n
+ mediump float maskTexture = texture2D( sMask, texCoord ).r;\n
- // Set the color of the text to what it is animated to.
- gl_FragColor = uTextColorAnimatable * textTexture * uColor * vec4( mixColor, opacity );\n
+ // Set the color of non-transparent pixel in text to what it is animated to.
+ // Markup text with multiple text colors are not animated (but can be supported later on if required).
+ // Emoji color are not animated.
+ mediump vec4 textColor = textTexture * textTexture.a;\n
+ mediump float vstep = step( 0.0001, textColor.a );\n
+ textColor.rgb = mix( textColor.rgb, uTextColorAnimatable.rgb, vstep * maskTexture * ( 1.0 - uHasMultipleTextColors ) );\n
+
+ // Draw the text as overlay above the style
+ gl_FragColor = ( textColor + styleTexture * ( 1.0 - textTexture.a ) ) * uColor * vec4( mixColor, opacity );\n
}\n
);
mControl = actor;
Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
- Shader shader = GetTextShader(mFactoryCache, true);
+ Shader shader = GetTextShader(mFactoryCache, TextType::SINGLE_COLOR_TEXT, TextType::NO_EMOJI, TextType::NO_STYLES);
mImpl->mRenderer = Renderer::New( geometry, shader );
mImpl->mRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, Toolkit::DepthIndex::CONTENT );
shadowEnabled = true;
}
- bool outlineWidthEnabled = false;
- float outlineWidth = mController->GetTextModel()->GetOutlineWidth();
- if ( outlineWidth > Math::MACHINE_EPSILON_1 )
- {
- outlineWidthEnabled = true;
- }
-
const bool underlineEnabled = mController->GetTextModel()->IsUnderlineEnabled();
+ const bool outlineEnabled = ( mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1 );
- if ( hasMultipleTextColors || containsEmoji || shadowEnabled || underlineEnabled || outlineWidthEnabled )
- {
- // Create RGBA textures if the text contains emojis or styles or multiple text colors
-
- // Create a texture for the text without any styles
- PixelData data = mTypesetter->Render( relayoutSize, Text::Typesetter::RENDER_NO_STYLES );
-
- // It may happen the image atlas can't handle a pixel data it exceeds the maximum size.
- // In that case, create a texture. TODO: should tile the text.
-
- Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
- data.GetPixelFormat(),
- data.GetWidth(),
- data.GetHeight() );
-
- texture.Upload( data );
-
- TextureSet textureSet = TextureSet::New();
- textureSet.SetTexture( 0u, texture );
-
- // Create a texture for all the text styles (without the text itself)
- PixelData styleData = mTypesetter->Render( relayoutSize, Text::Typesetter::RENDER_NO_TEXT );
-
- Texture styleTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
- styleData.GetPixelFormat(),
- styleData.GetWidth(),
- styleData.GetHeight() );
-
- styleTexture.Upload( styleData );
-
- textureSet.SetTexture( 1u, styleTexture );
-
- // Create a texture as a mask to avoid color glyphs (e.g. emojis) to be affected by text color animation
- PixelData maskData = mTypesetter->Render( relayoutSize, Text::Typesetter::RENDER_MASK );
-
- Texture maskTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
- styleData.GetPixelFormat(),
- styleData.GetWidth(),
- styleData.GetHeight() );
-
- maskTexture.Upload( maskData );
-
- textureSet.SetTexture( 2u, maskTexture );
-
- // Filter mode needs to be set to nearest to produce better quality while static.
- Sampler sampler = Sampler::New();
- sampler.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR );
- textureSet.SetSampler( 0u, sampler );
- textureSet.SetSampler( 1u, sampler );
- textureSet.SetSampler( 2u, sampler );
-
- mImpl->mRenderer.SetTextures( textureSet );
+ const bool styleEnabled = ( shadowEnabled || underlineEnabled || outlineEnabled );
- Shader shader = GetTextShader(mFactoryCache, true); // RGBA shader
- mImpl->mRenderer.SetShader(shader);
- }
- else
- {
- // Create L8 texture if the text contains only single text color with no emoji and no style
-
- // Create a texture for the text without any styles
- PixelData data = mTypesetter->Render( relayoutSize, Text::Typesetter::RENDER_NO_STYLES, false, Pixel::L8 );
-
- // It may happen the image atlas can't handle a pixel data it exceeds the maximum size.
- // In that case, create a texture. TODO: should tile the text.
-
- Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
- data.GetPixelFormat(),
- data.GetWidth(),
- data.GetHeight() );
-
- texture.Upload( data );
+ TextureSet textureSet = GetTextTexture( relayoutSize, hasMultipleTextColors, containsEmoji, styleEnabled );
+ mImpl->mRenderer.SetTextures( textureSet );
- TextureSet textureSet = TextureSet::New();
- textureSet.SetTexture( 0u, texture );
-
- // Filter mode needs to be set to nearest to produce better quality while static.
- Sampler sampler = Sampler::New();
- sampler.SetFilterMode( FilterMode::NEAREST, FilterMode::NEAREST );
- textureSet.SetSampler( 0u, sampler );
-
- mImpl->mRenderer.SetTextures( textureSet );
-
- Shader shader = GetTextShader(mFactoryCache, false); // L8 shader
- mImpl->mRenderer.SetShader(shader);
- }
+ Shader shader = GetTextShader( mFactoryCache, hasMultipleTextColors, containsEmoji, styleEnabled );
+ mImpl->mRenderer.SetShader(shader);
mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
}
}
-Shader TextVisual::GetTextShader( VisualFactoryCache& factoryCache, bool isRgbaTexture )
+TextureSet TextVisual::GetTextTexture( const Vector2& size, bool hasMultipleTextColors, bool containsEmoji, bool styleEnabled )
+{
+ // Filter mode needs to be set to linear to produce better quality while scaling.
+ Sampler sampler = Sampler::New();
+ sampler.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR );
+
+ TextureSet textureSet = TextureSet::New();
+
+ // Create RGBA texture if the text contains emojis or multiple text colors, otherwise L8 texture
+ Pixel::Format textPixelFormat = ( containsEmoji || hasMultipleTextColors ) ? Pixel::RGBA8888 : Pixel::L8;
+
+ // Create a texture for the text without any styles
+ PixelData data = mTypesetter->Render( size, 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.
+
+ Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
+ data.GetPixelFormat(),
+ data.GetWidth(),
+ data.GetHeight() );
+
+ texture.Upload( data );
+
+ textureSet.SetTexture( 0u, texture );
+ textureSet.SetSampler( 0u, sampler );
+
+ 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 );
+
+ Texture styleTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
+ styleData.GetPixelFormat(),
+ styleData.GetWidth(),
+ styleData.GetHeight() );
+
+ styleTexture.Upload( styleData );
+
+ textureSet.SetTexture( 1u, styleTexture );
+ textureSet.SetSampler( 1u, sampler );
+ }
+
+ 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 );
+
+ Texture maskTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
+ maskData.GetPixelFormat(),
+ maskData.GetWidth(),
+ maskData.GetHeight() );
+
+ maskTexture.Upload( maskData );
+
+ if ( !styleEnabled )
+ {
+ textureSet.SetTexture( 1u, maskTexture );
+ textureSet.SetSampler( 1u, sampler );
+ }
+ else
+ {
+ textureSet.SetTexture( 2u, maskTexture );
+ textureSet.SetSampler( 2u, sampler );
+ }
+ }
+
+ return textureSet;
+}
+
+Shader TextVisual::GetTextShader( VisualFactoryCache& factoryCache, bool hasMultipleTextColors, bool containsEmoji, bool styleEnabled )
{
Shader shader;
- if( isRgbaTexture )
+
+ if( hasMultipleTextColors && !styleEnabled )
+ {
+ // We don't animate text color if the text contains multiple colors
+ shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT );
+ if( !shader )
+ {
+ shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_MULTI_COLOR_TEXT );
+ shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+ factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT, shader );
+ }
+ }
+ else if( hasMultipleTextColors && styleEnabled )
+ {
+ // We don't animate text color if the text contains multiple colors
+ shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE );
+ if( !shader )
+ {
+ shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE );
+ shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+ factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE, shader );
+ }
+ }
+ else if( !hasMultipleTextColors && !containsEmoji && !styleEnabled )
+ {
+ shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT );
+ if( !shader )
+ {
+ shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_SINGLE_COLOR_TEXT );
+ shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+ factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT, shader );
+ }
+ }
+ else if( !hasMultipleTextColors && !containsEmoji && styleEnabled )
+ {
+ shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE );
+ if( !shader )
+ {
+ shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE );
+ shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+ factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE, shader );
+ }
+ }
+ else if( !hasMultipleTextColors && containsEmoji && !styleEnabled )
{
- shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_RGBA );
+ shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI );
if( !shader )
{
- shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_CLAMP_RGBA );
+ shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI );
shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
- factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_RGBA, shader );
+ factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI, shader );
}
}
- else
+ else // if( !hasMultipleTextColors && containsEmoji && styleEnabled )
{
- shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_L8 );
+ shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI );
if( !shader )
{
- shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_CLAMP_L8 );
+ shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI );
shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
- factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_L8, shader );
+ factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI, shader );
}
}
void RemoveTextureSet();
/**
+ * Get the texture of the text for rendering.
+ * @param[in] size The texture size.
+ * @param[in] hasMultipleTextColors Whether the text contains multiple colors.
+ * @param[in] containsEmoji Whether the text contains emoji.
+ * @param[in] styleEnabled Whether the text contains any styles (e.g. shadow, underline, etc.).
+ */
+ TextureSet GetTextTexture( const Vector2& size, bool hasMultipleTextColors, bool containsEmoji, bool styleEnabled );
+
+ /**
* Get the text rendering shader.
* @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
- * @param[in] isRgbaTexture Whether the texture is in RGBA format.
+ * @param[in] hasMultipleTextColors Whether the text contains multiple colors.
+ * @param[in] containsEmoji Whether the text contains emoji.
+ * @param[in] styleEnabled Whether the text contains any styles (e.g. shadow, underline, etc.).
*/
- Shader GetTextShader( VisualFactoryCache& factoryCache, bool isRgbaTexture );
+ Shader GetTextShader( VisualFactoryCache& factoryCache, bool hasMultipleTextColors, bool containsEmoji, bool styleEnabled );
/**
* @brief Retrieve the text's controller.
};
private:
+
+ /**
+ * Used as an alternative to boolean so that it is obvious whether the text contains single or multiple text colors, and emoji and styles.
+ */
+ struct TextType
+ {
+ enum Type
+ {
+ SINGLE_COLOR_TEXT = 0, ///< The text contains single color only.
+ MULTI_COLOR_TEXT = 1, ///< The text contains multiple colors.
+ NO_EMOJI = 0, ///< The text contains no emoji.
+ HAS_EMOJI = 1, ///< The text contains emoji.
+ NO_STYLES = 0, ///< The text contains contains no styles.
+ HAS_SYLES = 1 ///< The text contains contains styles.
+ };
+ };
+
+private:
Text::ControllerPtr mController; ///< The text's controller.
Text::TypesetterPtr mTypesetter; ///< The text's typesetter.
WeakHandle<Actor> mControl; ///< The control where the renderer is added.
// EXTERNAL HEADERS
#include <cstdlib>
#include <string>
+#include <dali/public-api/math/vector4.h>
#include <dali/devel-api/adaptor-framework/environment-variable.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
#include <dali/devel-api/common/hash.h>
#include <dali/devel-api/images/texture-set-image.h>
#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
// INTERNAL HEADERS
#include <dali-toolkit/internal/image-loader/image-atlas-impl.h>
#include <dali-toolkit/public-api/image-loader/sync-image-loader.h>
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
namespace
{
} // Anonymous namespace
+TextureManager::MaskingData::MaskingData()
+: mAlphaMaskUrl(),
+ mAlphaMaskId( INVALID_TEXTURE_ID ),
+ mContentScaleFactor( 1.0f ),
+ mCropToMask( true )
+{
+}
TextureManager::TextureManager()
: mAsyncLocalLoaders( GetNumberOfLocalLoaderThreads(), [&]() { return AsyncLoadingHelper(*this); } ),
{
}
+TextureSet TextureManager::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)
+{
+ TextureSet textureSet;
+
+ loadingStatus = false;
+ textureRect = FULL_ATLAS_RECT;
+
+ if( VisualUrl::TEXTURE == url.GetProtocolType())
+ {
+ std::string location = url.GetLocation();
+ if( location.size() > 0u )
+ {
+ TextureId id = std::stoi( location );
+ for( auto&& elem : mExternalTextures )
+ {
+ if( elem.textureId == id )
+ {
+ return elem.textureSet;
+ }
+ }
+ }
+ }
+ else if( synchronousLoading )
+ {
+ PixelData data;
+ if( url.IsValid() )
+ {
+ // if sync loading is required, the loading should immediately when actor is on stage
+ Devel::PixelBuffer pixelBuffer = LoadImageFromFile( url.GetUrl(), desiredSize, fittingMode, samplingMode );
+ if( pixelBuffer )
+ {
+ data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
+ }
+ }
+ if( !data )
+ {
+ // use broken image
+ textureSet = TextureSet::New();
+ Devel::PixelBuffer pixelBuffer = LoadImageFromFile( BROKEN_IMAGE_URL );
+ if( pixelBuffer )
+ {
+ data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
+ }
+ Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(),
+ data.GetWidth(), data.GetHeight() );
+ texture.Upload( data );
+ textureSet = TextureSet::New();
+ textureSet.SetTexture( 0u, texture );
+ }
+ else
+ {
+ if( atlasingStatus ) // attempt atlasing
+ {
+ textureSet = imageAtlasManager->Add( textureRect, data );
+ }
+ if( !textureSet ) // big image, no atlasing or atlasing failed
+ {
+ atlasingStatus = false;
+ Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(),
+ data.GetWidth(), data.GetHeight() );
+ texture.Upload( data );
+ textureSet = TextureSet::New();
+ textureSet.SetTexture( 0u, texture );
+ }
+ }
+ }
+ else
+ {
+ loadingStatus = true;
+ if( atlasingStatus )
+ {
+ textureSet = imageAtlasManager->Add( textureRect, url.GetUrl(), desiredSize, fittingMode, true, atlasObserver );
+ }
+ if( !textureSet ) // big image, no atlasing or atlasing failed
+ {
+ atlasingStatus = false;
+ if( !maskInfo )
+ {
+ textureId = RequestLoad( url, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS, textureObserver );
+ }
+ else
+ {
+ textureId = RequestLoad( url,
+ maskInfo->mAlphaMaskId,
+ maskInfo->mContentScaleFactor,
+ desiredSize,
+ fittingMode, samplingMode,
+ TextureManager::NO_ATLAS,
+ maskInfo->mCropToMask,
+ textureObserver );
+ }
+
+ TextureManager::LoadState loadState = GetTextureState( textureId );
+ loadingStatus = ( loadState == TextureManager::LOADING );
+
+ if( loadState == TextureManager::UPLOADED )
+ {
+ // UploadComplete has already been called - keep the same texture set
+ textureSet = GetTextureSet( textureId );
+ }
+ }
+ }
+
+ if( ! atlasingStatus && textureSet )
+ {
+ Sampler sampler = Sampler::New();
+ sampler.SetWrapMode( wrapModeU, wrapModeV );
+ textureSet.SetSampler( 0u, sampler );
+ }
+
+ return textureSet;
+}
+
TextureManager::TextureId TextureManager::RequestLoad(
const VisualUrl& url,
const ImageDimensions desiredSize,
return RequestLoadInternal( maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, NO_ATLAS, false, KEEP_PIXEL_BUFFER, NULL );
}
-
TextureManager::TextureId TextureManager::RequestLoadInternal(
const VisualUrl& url,
TextureId maskTextureId,
}
}
-TextureManager::~TextureManager()
-{
-}
-
TextureManager::AsyncLoadingHelper::AsyncLoadingHelper(TextureManager& textureManager)
: AsyncLoadingHelper(Toolkit::AsyncImageLoader::New(), textureManager,
AsyncLoadingInfoContainerType())
#include <deque>
#include <functional>
#include <string>
+#include <memory>
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/object/ref-object.h>
#include <dali/public-api/rendering/texture-set.h>
namespace Internal
{
+class ImageAtlasManager;
+typedef IntrusivePtr<ImageAtlasManager> ImageAtlasManagerPtr;
/**
* The TextureManager provides a common Image loading API for Visuals.
public:
+ struct MaskingData
+ {
+ MaskingData();
+ ~MaskingData() = default;
+
+ VisualUrl mAlphaMaskUrl;
+ TextureManager::TextureId mAlphaMaskId;
+ float mContentScaleFactor;
+ bool mCropToMask;
+ };
+ using MaskingDataPointer = std::unique_ptr<MaskingData>;
+
/**
* Constructor.
*/
/**
* Destructor.
*/
- ~TextureManager();
+ ~TextureManager() = default;
// 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);
+
/**
* @brief Requests an image load of the given URL.
*
unsigned short loadId; ///< The load Id used by the async loader to reference this load
};
- /**
- * @brief This struct is used within a container to manage atlas creation and destruction.
- */
- struct AtlasInfo
- {
- AtlasInfo( Toolkit::ImageAtlas atlas, TextureSet textureSet )
- : atlas( atlas ),
- textureSet( textureSet )
- {
- }
-
- Toolkit::ImageAtlas atlas; ///< The ImageAtlas object
- TextureSet textureSet; ///< The TextureSet is kept in the struct to allow fast lookup of TextureSet to Atlas
- };
-
// Private typedefs:
typedef std::deque<AsyncLoadingInfo> AsyncLoadingInfoContainerType; ///< The container type used to manage Asynchronous loads in progress
- typedef std::vector<AtlasInfo> AtlasInfoContainerType; ///< The container type used to manage Atlas creation and destruction
typedef std::vector<TextureInfo> TextureInfoContainerType; ///< The container type used to manage the life-cycle and caching of Textures
/**
private: // Member Variables:
- AtlasInfoContainerType mAtlasContainer; ///< Used to manage Atlas creation and destruction
TextureInfoContainerType mTextureInfoContainer; ///< Used to manage the life-cycle and caching of Textures
RoundRobinContainerView< AsyncLoadingHelper > mAsyncLocalLoaders; ///< The Asynchronous image loaders used to provide all local async loads
RoundRobinContainerView< AsyncLoadingHelper > mAsyncRemoteLoaders; ///< The Asynchronous image loaders used to provide all remote async loads
IMAGE_SHADER_ATLAS_CUSTOM_WRAP,
NINE_PATCH_SHADER,
SVG_SHADER,
- TEXT_SHADER_RGBA,
- TEXT_SHADER_L8,
+ TEXT_SHADER_MULTI_COLOR_TEXT,
+ TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE,
+ TEXT_SHADER_SINGLE_COLOR_TEXT,
+ TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE,
+ TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI,
+ TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI,
WIREFRAME_SHADER,
SHADER_TYPE_MAX = WIREFRAME_SHADER
};
const unsigned int TOOLKIT_MAJOR_VERSION = 1;
const unsigned int TOOLKIT_MINOR_VERSION = 2;
-const unsigned int TOOLKIT_MICRO_VERSION = 58;
+const unsigned int TOOLKIT_MICRO_VERSION = 59;
const char * const TOOLKIT_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
Name: dali-toolkit
Summary: Dali 3D engine Toolkit
-Version: 1.2.58
+Version: 1.2.59
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT
##############################
%preun resources_480x800
-pushd %{dali_toolkit_style_files}
-mv images ./480x800
-mv dali-toolkit-default-theme.json ./480x800
-popd
+case "$1" in
+ 0)
+ %preun resources_480x800
+ pushd %{dali_toolkit_style_files}
+ mv images ./480x800
+ mv dali-toolkit-default-theme.json ./480x800
+ popd
+ ;;
+esac
%preun resources_720x1280
-pushd %{dali_toolkit_style_files}
-mv images ./720x1280
-mv dali-toolkit-default-theme.json ./720x1280
-popd
+case "$1" in
+ 0)
+ %preun resources_720x1280
+ pushd %{dali_toolkit_style_files}
+ mv images ./720x1280
+ mv dali-toolkit-default-theme.json ./720x1280
+ popd
+ ;;
+esac
%preun resources_1920x1080
-pushd %{dali_toolkit_style_files}
-mv images ./1920x1080
-mv dali-toolkit-default-theme.json ./1920x1080
-popd
+case "$1" in
+ 0)
+ %preun resources_1920x1080
+ pushd %{dali_toolkit_style_files}
+ mv images ./1920x1080
+ mv dali-toolkit-default-theme.json ./1920x1080
+ popd
+ ;;
+esac
##############################
# Post Uninstall