Reduce memory consumption of TextLabel by reducing texture size 38/164338/12
authorRichard Huang <r.huang@samsung.com>
Mon, 18 Dec 2017 17:42:14 +0000 (17:42 +0000)
committerRichard Huang <r.huang@samsung.com>
Wed, 3 Jan 2018 10:52:14 +0000 (10:52 +0000)
Change-Id: Ia7350a410d8f308b709bda2e4829eab3dc2ceebf

automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Typesetter.cpp
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/text/rendering/text-typesetter.cpp
dali-toolkit/internal/text/rendering/text-typesetter.h
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/visuals/text/text-visual.cpp

index 14f352c..44136a7 100644 (file)
@@ -27,6 +27,7 @@
 #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;
@@ -108,7 +109,7 @@ int UtcDaliTextRenderingControllerRender(void)
   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 );
@@ -120,7 +121,7 @@ int UtcDaliTextRenderingControllerRender(void)
   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 );
@@ -131,7 +132,7 @@ int UtcDaliTextRenderingControllerRender(void)
   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 );
@@ -166,32 +167,32 @@ int UtcDaliTextTypesetterVerticalLineAlignment(void)
   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
+}
index 0cbb799..d1dff13 100644 (file)
@@ -60,6 +60,19 @@ namespace Internal
 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
@@ -940,10 +953,29 @@ void TextLabel::OnRelayout( const Vector2& size, RelayoutContainer& container )
       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 );
@@ -1003,7 +1035,7 @@ void TextLabel::SetUpAutoScrolling()
 
   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(),
index 314bc63..901c477 100755 (executable)
@@ -267,7 +267,7 @@ ViewModel* Typesetter::GetViewModel()
   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.
 
@@ -277,8 +277,32 @@ PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bo
   // 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() )
   {
@@ -340,7 +364,7 @@ PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bo
   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 )
   {
@@ -351,7 +375,7 @@ PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bo
   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 ) )
@@ -362,7 +386,7 @@ PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bo
     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 );
@@ -375,7 +399,7 @@ PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bo
     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();
@@ -394,7 +418,7 @@ PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bo
     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 );
@@ -407,7 +431,7 @@ PixelData Typesetter::Render( const Vector2& size, RenderBehaviour behaviour, bo
   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();
@@ -451,6 +475,7 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer( const unsigned int bufferWidth
 
     // 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 );
index 285348e..453541b 100644 (file)
@@ -25,6 +25,7 @@
 #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
 {
@@ -102,13 +103,14 @@ public:
    * - 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:
   /**
@@ -137,13 +139,14 @@ 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.
index d454031..98862db 100755 (executable)
@@ -3422,7 +3422,8 @@ bool Controller::DoRelayout( const Size& size,
     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(),
index e44b005..e4c62f8 100755 (executable)
@@ -35,6 +35,7 @@
 #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
 {
@@ -697,7 +698,7 @@ void TextVisual::UpdateRenderer()
 
       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 );
@@ -752,8 +753,11 @@ TextureSet TextVisual::GetTextTexture( const Vector2& size, bool hasMultipleText
   // 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.
@@ -771,7 +775,7 @@ TextureSet TextVisual::GetTextTexture( const Vector2& size, bool hasMultipleText
   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(),
@@ -787,7 +791,7 @@ TextureSet TextVisual::GetTextTexture( const Vector2& size, bool hasMultipleText
   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(),