Create single channel texture for text with no styles and emojis.
Change-Id: I14363763fe7c7422a2a555d8a9ba0b68e1ab575b
// Create a texture of the text for scrolling
Text::TypesetterPtr typesetter = Text::Typesetter::New( mController->GetTextModel() );
- PixelData data = typesetter->Render( textNaturalSize, Text::Typesetter::RENDER_TEXT_AND_STYLES, true ); // ignore the horizontal alignment
+ PixelData data = typesetter->Render( textNaturalSize, 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(),
* @param[in] position The position of the glyph.
* @param[in] color The color of the glyph.
* @param[in] style The style of the text.
+ * @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).
*/
void TypesetGlyph( GlyphData& data,
const Vector2* const position,
const Vector4* const color,
- Typesetter::Style style)
+ Typesetter::Style style,
+ Pixel::Format pixelFormat )
{
if( ( 0u == data.glyphBitmap.width ) || ( 0u == data.glyphBitmap.height ) )
{
const int widthMinusOne = static_cast<int>( data.width - 1u );
const int heightMinusOne = static_cast<int>( data.height - 1u );
- // Whether the given glyph is a color one.
- const bool isColorGlyph = Pixel::BGRA8888 == data.glyphBitmap.format;
-
- // Pointer to the color glyph if there is one.
- const uint32_t* const colorGlyphBuffer = isColorGlyph ? reinterpret_cast<uint32_t*>( data.glyphBitmap.buffer ) : NULL;
+ if ( Pixel::RGBA8888 == pixelFormat )
+ {
+ // Whether the given glyph is a color one.
+ const bool isColorGlyph = Pixel::BGRA8888 == data.glyphBitmap.format;
- // Pack the given color into a 32bit buffer. The alpha channel will be updated later for each pixel.
- // The format is RGBA8888.
- uint32_t packedColor = 0u;
- uint8_t* packedColorBuffer = reinterpret_cast<uint8_t*>( &packedColor );
- *( packedColorBuffer + 2 ) = static_cast<uint8_t>( color->b * 255.f );
- *( packedColorBuffer + 1 ) = static_cast<uint8_t>( color->g * 255.f );
- *packedColorBuffer = static_cast<uint8_t>( color->r * 255.f );
+ // Pointer to the color glyph if there is one.
+ const uint32_t* const colorGlyphBuffer = isColorGlyph ? reinterpret_cast<uint32_t*>( data.glyphBitmap.buffer ) : NULL;
- // Initial vertical offset.
- const int yOffset = data.verticalOffset + position->y;
+ // Pack the given color into a 32bit buffer. The alpha channel will be updated later for each pixel.
+ // The format is RGBA8888.
+ uint32_t packedColor = 0u;
+ uint8_t* packedColorBuffer = reinterpret_cast<uint8_t*>( &packedColor );
+ *( packedColorBuffer + 2 ) = static_cast<uint8_t>( color->b * 255.f );
+ *( packedColorBuffer + 1 ) = static_cast<uint8_t>( color->g * 255.f );
+ *packedColorBuffer = static_cast<uint8_t>( color->r * 255.f );
- // Traverse the pixels of the glyph line per line.
- for( int lineIndex = 0, glyphHeight = static_cast<int>( data.glyphBitmap.height ); lineIndex < glyphHeight; ++lineIndex )
- {
- const int yOffsetIndex = yOffset + lineIndex;
- if( ( 0 > yOffsetIndex ) || ( yOffsetIndex > heightMinusOne ) )
- {
- // Do not write out of bounds.
- break;
- }
+ // Initial vertical offset.
+ const int yOffset = data.verticalOffset + position->y;
- const int verticalOffset = yOffsetIndex * data.width;
- const int xOffset = data.horizontalOffset + position->x;
- const int glyphBufferOffset = lineIndex * static_cast<int>( data.glyphBitmap.width );
- for( int index = 0, glyphWidth = static_cast<int>( data.glyphBitmap.width ); index < glyphWidth; ++index )
+ // Traverse the pixels of the glyph line per line.
+ for( int lineIndex = 0, glyphHeight = static_cast<int>( data.glyphBitmap.height ); lineIndex < glyphHeight; ++lineIndex )
{
- const int xOffsetIndex = xOffset + index;
- if( ( 0 > xOffsetIndex ) || ( xOffsetIndex > widthMinusOne ) )
+ const int yOffsetIndex = yOffset + lineIndex;
+ if( ( 0 > yOffsetIndex ) || ( yOffsetIndex > heightMinusOne ) )
{
- // Don't write out of bounds.
+ // Do not write out of bounds.
break;
}
- uint32_t* bitmapBuffer = reinterpret_cast< uint32_t* >( data.bitmapBuffer.GetBuffer() );
-
- if( isColorGlyph )
+ const int verticalOffset = yOffsetIndex * data.width;
+ const int xOffset = data.horizontalOffset + position->x;
+ const int glyphBufferOffset = lineIndex * static_cast<int>( data.glyphBitmap.width );
+ for( int index = 0, glyphWidth = static_cast<int>( data.glyphBitmap.width ); index < glyphWidth; ++index )
{
- // Retrieves the color from the color glyph. The format is BGRA8888.
- uint32_t packedColorGlyph = *( colorGlyphBuffer + glyphBufferOffset + index );
- uint8_t* packedColorGlyphBuffer = reinterpret_cast<uint8_t*>( &packedColorGlyph );
-
- if( Typesetter::STYLE_SHADOW == style )
+ const int xOffsetIndex = xOffset + index;
+ if( ( 0 > xOffsetIndex ) || ( xOffsetIndex > widthMinusOne ) )
{
- // The shadow of color glyph needs to have the shadow color.
- *( packedColorGlyphBuffer + 2 ) = static_cast<uint8_t>( color->b * 255.f );
- *( packedColorGlyphBuffer + 1 ) = static_cast<uint8_t>( color->g * 255.f );
- *packedColorGlyphBuffer = static_cast<uint8_t>( color->r * 255.f );
- }
- else
- {
- std::swap( *packedColorGlyphBuffer, *( packedColorGlyphBuffer + 2u ) ); // Swap B and R.
+ // Don't write out of bounds.
+ break;
}
- // Update the alpha channel.
- if( Typesetter::STYLE_MASK == style )
+ uint32_t* bitmapBuffer = reinterpret_cast< uint32_t* >( data.bitmapBuffer.GetBuffer() );
+
+ if( isColorGlyph )
{
- // Create an alpha mask for color glyph.
- *( packedColorGlyphBuffer + 3u ) = 0u;
+ // Retrieves the color from the color glyph. The format is BGRA8888.
+ uint32_t packedColorGlyph = *( colorGlyphBuffer + glyphBufferOffset + index );
+ uint8_t* packedColorGlyphBuffer = reinterpret_cast<uint8_t*>( &packedColorGlyph );
+
+ if( Typesetter::STYLE_SHADOW == style )
+ {
+ // The shadow of color glyph needs to have the shadow color.
+ *( packedColorGlyphBuffer + 2 ) = static_cast<uint8_t>( color->b * 255.f );
+ *( packedColorGlyphBuffer + 1 ) = static_cast<uint8_t>( color->g * 255.f );
+ *packedColorGlyphBuffer = static_cast<uint8_t>( color->r * 255.f );
+ }
+ else
+ {
+ std::swap( *packedColorGlyphBuffer, *( packedColorGlyphBuffer + 2u ) ); // Swap B and R.
+ }
+
+ // Update the alpha channel.
+ if( Typesetter::STYLE_MASK == style )
+ {
+ // Create an alpha mask for color glyph.
+ *( packedColorGlyphBuffer + 3u ) = 0u;
+ }
+ else
+ {
+ *( packedColorGlyphBuffer + 3u ) = static_cast<uint8_t>( color->a * static_cast<float>( *( packedColorGlyphBuffer + 3u ) ) );
+ }
+
+ // Set the color into the final pixel buffer.
+ *( bitmapBuffer + verticalOffset + xOffsetIndex ) = packedColorGlyph;
}
else
{
- *( packedColorGlyphBuffer + 3u ) = static_cast<uint8_t>( color->a * static_cast<float>( *( packedColorGlyphBuffer + 3u ) ) );
+ // 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
+ uint32_t& currentColor = *( bitmapBuffer + verticalOffset + xOffsetIndex );
+ uint8_t* packedCurrentColorBuffer = reinterpret_cast<uint8_t*>( ¤tColor );
+
+ uint8_t currentAlpha = *( packedCurrentColorBuffer + 3u );
+ 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).
+ *( packedColorBuffer + 3u ) = std::max( currentAlpha, newAlpha );
+
+ // Set the color into the final pixel buffer.
+ currentColor = packedColor;
+ }
}
+ }
+ }
+ }
+ else
+ {
+ // Initial vertical offset.
+ const int yOffset = data.verticalOffset + position->y;
- // Set the color into the final pixel buffer.
- *( bitmapBuffer + verticalOffset + xOffsetIndex ) = packedColorGlyph;
+ // Traverse the pixels of the glyph line per line.
+ for( int lineIndex = 0, glyphHeight = static_cast<int>( data.glyphBitmap.height ); lineIndex < glyphHeight; ++lineIndex )
+ {
+ const int yOffsetIndex = yOffset + lineIndex;
+ if( ( 0 > yOffsetIndex ) || ( yOffsetIndex > heightMinusOne ) )
+ {
+ // Do not write out of bounds.
+ break;
}
- else
+
+ const int verticalOffset = yOffsetIndex * data.width;
+ const int xOffset = data.horizontalOffset + position->x;
+ const int glyphBufferOffset = lineIndex * static_cast<int>( data.glyphBitmap.width );
+ for( int index = 0, glyphWidth = static_cast<int>( data.glyphBitmap.width ); index < glyphWidth; ++index )
{
+ const int xOffsetIndex = xOffset + index;
+ if( ( 0 > xOffsetIndex ) || ( xOffsetIndex > widthMinusOne ) )
+ {
+ // Don't write out of bounds.
+ break;
+ }
+
+ uint8_t* bitmapBuffer = reinterpret_cast< uint8_t* >( data.bitmapBuffer.GetBuffer() );
+
// Update the alpha channel.
const uint8_t alpha = *( data.glyphBitmap.buffer + glyphBufferOffset + index );
if ( alpha > 0u )
{
// Check alpha of overlapped pixels
- uint32_t& currentColor = *( bitmapBuffer + verticalOffset + xOffsetIndex );
- uint8_t* packedCurrentColorBuffer = reinterpret_cast<uint8_t*>( ¤tColor );
-
- uint8_t currentAlpha = *( packedCurrentColorBuffer + 3u );
+ uint8_t& currentAlpha = *( bitmapBuffer + verticalOffset + xOffsetIndex );
uint8_t newAlpha = static_cast<uint8_t>( color->a * static_cast<float>( alpha ) );
+// printf("y: %d, x: %d: alpha: %u, currentAlpha: %u, newAlpha: %u, a: %u\n", yOffsetIndex, xOffsetIndex, alpha, currentAlpha, newAlpha, std::max( currentAlpha, newAlpha ) );
// 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).
- *( packedColorBuffer + 3u ) = std::max( currentAlpha, newAlpha );
-
- // Set the color into the final pixel buffer.
- currentColor = packedColor;
+ *( bitmapBuffer + verticalOffset + xOffsetIndex ) = std::max( currentAlpha, newAlpha );
}
}
}
return mModel;
}
-PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bool ignoreHorizontalAlignment )
+PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat )
{
// @todo. This initial implementation for a TextLabel has only one visible page.
if( RENDER_MASK == behaviour )
{
// Generate the image buffer as an alpha mask for color glyphs.
- imageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_MASK, ignoreHorizontalAlignment, penY, 0u, numberOfGlyphs - 1 );
+ imageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_MASK, ignoreHorizontalAlignment, pixelFormat, 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, penY, 0u, numberOfGlyphs -1 );
+ imageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_NONE, ignoreHorizontalAlignment, pixelFormat, penY, 0u, numberOfGlyphs -1 );
}
if ( ( RENDER_NO_STYLES != behaviour ) && ( RENDER_MASK != behaviour ) )
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, penY, 0u, numberOfGlyphs - 1 );
+ Devel::PixelBuffer shadowImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_SHADOW, ignoreHorizontalAlignment, pixelFormat, penY, 0u, numberOfGlyphs - 1 );
// Combine the two buffers
imageBuffer = CombineImageBuffer( imageBuffer, shadowImageBuffer, bufferWidth, bufferHeight );
if ( underlineEnabled )
{
// Create the image buffer for underline
- Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, penY, 0u, numberOfGlyphs - 1 );
+ Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, 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, 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 verticalOffset, GlyphIndex fromGlyphIndex, GlyphIndex toGlyphIndex )
{
// Retrieve lines, glyphs, positions and colors from the view model.
const Length modelNumberOfLines = mModel->GetNumberOfLines();
// Create and initialize the pixel buffer.
GlyphData glyphData;
glyphData.verticalOffset = verticalOffset;
-
glyphData.width = bufferWidth;
glyphData.height = bufferHeight;
- const unsigned int bufferSizeInt = bufferWidth * bufferHeight;
- const unsigned int bufferSizeChar = 4u * bufferSizeInt;
- glyphData.bitmapBuffer = Devel::PixelBuffer::New( bufferWidth, bufferHeight, Pixel::RGBA8888 );
- memset( glyphData.bitmapBuffer.GetBuffer(), 0u, bufferSizeChar );
+ glyphData.bitmapBuffer = Devel::PixelBuffer::New( bufferWidth, bufferHeight, pixelFormat );
+
+ if ( Pixel::RGBA8888 == pixelFormat )
+ {
+ const unsigned int bufferSizeInt = bufferWidth * bufferHeight;
+ const unsigned int bufferSizeChar = 4u * bufferSizeInt;
+ memset( glyphData.bitmapBuffer.GetBuffer(), 0u, bufferSizeChar );
+ }
+ else
+ {
+ memset( glyphData.bitmapBuffer.GetBuffer(), 0, bufferWidth * bufferHeight );
+ }
// Get a handle of the font client. Used to retrieve the bitmaps of the glyphs.
TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
TypesetGlyph( glyphData,
position,
color,
- style );
+ style,
+ pixelFormat);
// delete the glyphBitmap.buffer as it is now copied into glyphData.bitmapBuffer
delete []glyphData.glyphBitmap.buffer;
glyphData.glyphBitmap.buffer = NULL;
break;
}
+ // Always RGBA image for text with styles
uint32_t* bitmapBuffer = reinterpret_cast< uint32_t* >( glyphData.bitmapBuffer.GetBuffer() );
uint32_t underlinePixel = *( bitmapBuffer + y * glyphData.width + x );
uint8_t* underlinePixelBuffer = reinterpret_cast<uint8_t*>( &underlinePixel );
return topPixelBuffer;
}
+ // Always combine two RGBA images
const unsigned int bufferSizeInt = bufferWidth * bufferHeight;
const unsigned int bufferSizeChar = 4u * bufferSizeInt;
// EXTERNAL INCLUDES
#include <dali/public-api/common/intrusive-ptr.h>
#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/images/pixel.h>
#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>
* @param[in] size The renderer size.
* @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 );
+ PixelData Render( const Vector2& size, RenderBehaviour behaviour = RENDER_TEXT_AND_STYLES, bool ignoreHorizontalAlignment = false, Pixel::Format pixelFormat = Pixel::RGBA8888 );
private:
/**
* @param[in] bufferHeight The height of the image buffer.
* @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] 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, 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 verticalOffset, TextAbstraction::GlyphIndex fromGlyphIndex, TextAbstraction::GlyphIndex toGlyphIndex );
/**
- * @brief Combine the two image buffers together.
+ * @brief Combine the two RGBA image buffers together.
*
* The top layer buffer will blend over the bottom layer buffer:
* - If the pixel is not fully opaque from either buffer, it will be blended with
* @return The combined image buffer with the text.
*
*/
- Devel::PixelBuffer CombineImageBuffer( Devel::PixelBuffer topPixelBuffer, Devel::PixelBuffer bottomPixelBuffer, const unsigned int bufferWidth, const unsigned int bufferHeight );
+ Devel::PixelBuffer CombineImageBuffer( Devel::PixelBuffer topPixelBuffer, Devel::PixelBuffer bottomPixelBuffer, const unsigned int bufferWidth, const unsigned int bufferHeightbool );
protected:
return mModel->GetLines();
}
+Length ViewModel::GetNumberOfScripts() const
+{
+ return mModel->GetNumberOfScripts();
+}
+
+const ScriptRun* const ViewModel::GetScriptRuns() const
+{
+ return mModel->GetScriptRuns();
+}
+
Length ViewModel::GetNumberOfGlyphs() const
{
if( mIsTextElided && mModel->IsTextElideEnabled() )
virtual const LineRun* const GetLines() const;
/**
+ * @copydoc ModelInterface::GetNumberOfScripts()
+ */
+ virtual Length GetNumberOfScripts() const;
+
+ /**
+ * @copydoc ModelInterface::GetScriptRuns()
+ */
+ virtual const ScriptRun* const GetScriptRuns() const;
+
+ /**
* @copydoc ModelInterface::GetNumberOfGlyphs()
*/
virtual Length GetNumberOfGlyphs() const;
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/layouts/layout-alignment.h>
#include <dali-toolkit/internal/text/line-run.h>
+#include <dali-toolkit/internal/text/script-run.h>
#include <dali-toolkit/internal/text/text-definitions.h>
namespace Dali
virtual const LineRun* const GetLines() const = 0;
/**
+ * @brief Retrieves the number of script runs.
+ *
+ * @return The number of script runs.
+ */
+ virtual Length GetNumberOfScripts() const = 0;
+
+ /**
+ * @brief Retrieves the script runs.
+ *
+ * @return A pointer to the vector with the runs of characters with the same script..
+ */
+ virtual const ScriptRun* const GetScriptRuns() const = 0;
+
+ /**
* @brief Retrieves the number of laid-out glyphs.
*
* @return The number of laid-out glyphs.
return mVisualModel->mLines.Begin();
}
+Length Model::GetNumberOfScripts() const
+{
+ return mLogicalModel->mScriptRuns.Count();
+}
+
+const ScriptRun* const Model::GetScriptRuns() const
+{
+ return mLogicalModel->mScriptRuns.Begin();
+}
+
Length Model::GetNumberOfGlyphs() const
{
return mVisualModel->mGlyphs.Count();
virtual const LineRun* const GetLines() const;
/**
+ * @copydoc ModelInterface::GetNumberOfScripts()
+ */
+ virtual Length GetNumberOfScripts() const;
+
+ /**
+ * @copydoc ModelInterface::GetScriptRuns()
+ */
+ virtual const ScriptRun* const GetScriptRuns() const;
+
+ /**
* @copydoc ModelInterface::GetNumberOfGlyphs()
*/
virtual Length GetNumberOfGlyphs() const;
// EXTERNAL INCLUDES
#include <dali/public-api/animation/constraints.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
// INTERNAL HEADER
#include <dali-toolkit/devel-api/visuals/text-visual-properties.h>
#include <dali-toolkit/internal/visuals/visual-string-constants.h>
#include <dali-toolkit/internal/text/text-font-style.h>
#include <dali-toolkit/internal/text/text-effects-style.h>
+#include <dali-toolkit/internal/text/script-run.h>
namespace Dali
{
}\n
);
-const char* FRAGMENT_SHADER_ATLAS_CLAMP = DALI_COMPOSE_SHADER(
+const char* FRAGMENT_SHADER_ATLAS_CLAMP_RGBA = DALI_COMPOSE_SHADER(
varying mediump vec2 vTexCoord;\n
uniform sampler2D sTexture;\n
uniform sampler2D sStyle;\n
}\n
);
+const char* FRAGMENT_SHADER_ATLAS_CLAMP_L8 = 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
+ }\n
+);
+
/**
* Return Property index for the given string key
* param[in] stringKey the string index key
mControl = actor;
Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
-
- Shader shader = mFactoryCache.GetShader( VisualFactoryCache::TEXT_SHADER );
- if( ! shader )
- {
- shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_CLAMP );
- shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
-
- mFactoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER, shader );
- }
+ Shader shader = GetTextShader(mFactoryCache, true);
mImpl->mRenderer = Renderer::New( geometry, shader );
mImpl->mRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, Toolkit::DepthIndex::CONTENT );
if( ( relayoutSize.width > Math::MACHINE_EPSILON_1000 ) &&
( relayoutSize.height > Math::MACHINE_EPSILON_1000 ) )
{
- Vector4 atlasRect = FULL_TEXTURE_RECT;
+ // Check whether it is a markup text with multiple text colors
+ const Vector4* const colorsBuffer = mController->GetTextModel()->GetColors();
+ bool hasMultipleTextColors = ( NULL != colorsBuffer );
+
+ // Check whether the text contains any emoji
+ bool containsEmoji = false;
- // Create a texture for the text without any styles
- PixelData data = mTypesetter->Render( relayoutSize, Text::Typesetter::RENDER_NO_STYLES );
+ Text::ScriptRunIndex numberOfScripts = mController->GetTextModel()->GetNumberOfScripts();
+ const Text::ScriptRun* scripts = mController->GetTextModel()->GetScriptRuns();
+ for ( Text::ScriptRunIndex scriptIndex = 0u; scriptIndex < numberOfScripts; scriptIndex++ )
+ {
+ const Text::ScriptRun& scriptRun = *( scripts + scriptIndex );
+ if( TextAbstraction::EMOJI == scriptRun.script )
+ {
+ containsEmoji = true;
+ break;
+ }
+ }
+
+ // Check whether the text contains any style colors (e.g. underline color, shadow color, etc.)
+ bool shadowEnabled = false;
+ const Vector2& shadowOffset = mController->GetTextModel()->GetShadowOffset();
+ if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 )
+ {
+ shadowEnabled = true;
+ }
+
+ const bool underlineEnabled = mController->GetTextModel()->IsUnderlineEnabled();
+
+ if ( hasMultipleTextColors || containsEmoji || shadowEnabled || underlineEnabled )
+ {
+ // Create RGBA textures if the text contains emojis or styles or multiple text colors
- // 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.
+ // Create a texture for the text without any styles
+ PixelData data = mTypesetter->Render( relayoutSize, Text::Typesetter::RENDER_NO_STYLES );
- Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
- data.GetPixelFormat(),
- data.GetWidth(),
- data.GetHeight() );
+ // 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.Upload( data );
+ Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
+ data.GetPixelFormat(),
+ data.GetWidth(),
+ data.GetHeight() );
- TextureSet textureSet = TextureSet::New();
- textureSet.SetTexture( 0u, texture );
+ texture.Upload( data );
- // Create a texture for all the text styles (without the text itself)
- PixelData styleData = mTypesetter->Render( relayoutSize, Text::Typesetter::RENDER_NO_TEXT );
+ TextureSet textureSet = TextureSet::New();
+ textureSet.SetTexture( 0u, texture );
- Texture styleTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
- styleData.GetPixelFormat(),
- styleData.GetWidth(),
- styleData.GetHeight() );
+ // Create a texture for all the text styles (without the text itself)
+ PixelData styleData = mTypesetter->Render( relayoutSize, Text::Typesetter::RENDER_NO_TEXT );
- styleTexture.Upload( styleData );
+ Texture styleTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
+ styleData.GetPixelFormat(),
+ styleData.GetWidth(),
+ styleData.GetHeight() );
- textureSet.SetTexture( 1u, styleTexture );
+ styleTexture.Upload( styleData );
- // 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 );
+ textureSet.SetTexture( 1u, styleTexture );
- Texture maskTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
- styleData.GetPixelFormat(),
- styleData.GetWidth(),
- styleData.GetHeight() );
+ // 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 );
- maskTexture.Upload( maskData );
+ Texture maskTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
+ styleData.GetPixelFormat(),
+ styleData.GetWidth(),
+ styleData.GetHeight() );
- textureSet.SetTexture( 2u, maskTexture );
+ maskTexture.Upload( maskData );
- // 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.SetSampler( 0u, sampler );
- textureSet.SetSampler( 1u, sampler );
- textureSet.SetSampler( 2u, sampler );
+ textureSet.SetTexture( 2u, maskTexture );
- mImpl->mRenderer.SetTextures( textureSet );
+ // 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 );
+
+ 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 = 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);
+ }
mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
+ Vector4 atlasRect = FULL_TEXTURE_RECT;
mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect );
-
- // Check whether it is a markup text with multiple text colors
- const Vector4* const colorsBuffer = mController->GetTextModel()->GetColors();
- bool hasMultipleTextColors = ( NULL != colorsBuffer );
mImpl->mRenderer.RegisterProperty( "uHasMultipleTextColors", static_cast<float>( hasMultipleTextColors ) );
+ mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON);
+
//Register transform properties
mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
}
}
+Shader TextVisual::GetTextShader( VisualFactoryCache& factoryCache, bool isRgbaTexture )
+{
+ Shader shader;
+ if( isRgbaTexture )
+ {
+ shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_RGBA );
+ if( !shader )
+ {
+ shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_CLAMP_RGBA );
+ shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+ factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_RGBA, shader );
+ }
+ }
+ else
+ {
+ shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_L8 );
+ if( !shader )
+ {
+ shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_CLAMP_L8 );
+ shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+ factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_L8, shader );
+ }
+ }
+
+ return shader;
+}
+
} // namespace Internal
} // namespace Toolkit
void RemoveTextureSet();
/**
+ * 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.
+ */
+ Shader GetTextShader( VisualFactoryCache& factoryCache, bool isRgbaTexture );
+
+ /**
* @brief Retrieve the text's controller.
* @param[in] visual The text visual.
* @return The text controller
IMAGE_SHADER_ATLAS_CUSTOM_WRAP,
NINE_PATCH_SHADER,
SVG_SHADER,
- TEXT_SHADER,
+ TEXT_SHADER_RGBA,
+ TEXT_SHADER_L8,
WIREFRAME_SHADER,
SHADER_TYPE_MAX = WIREFRAME_SHADER
};