[Tizen] Integration TextUtils from tizen_6.0 to tizen_5.5 59/253059/1
authorJoogab Yun <joogab.yun@samsung.com>
Tue, 2 Feb 2021 04:15:28 +0000 (13:15 +0900)
committerJoogab Yun <joogab.yun@samsung.com>
Thu, 4 Feb 2021 06:06:23 +0000 (15:06 +0900)
    Add MIN_LINE_SIZE property

    Users want to set the line size in multi-line.
    We have a lineSpacing property which allows us to set the spacing of the lines.

    However, the user wants to achieve a similar effect by setting the size of the line, not lineSpacing.

    Change-Id: Ia96e1875e90454a3269d2ad853d3c4e20ce66ae9

    Change Resize() to Reserve() to improve performance.

    Change-Id: I6078fb17131630a770cb770dc9f2251f1c9ae6b6

    Divide Render() into small apis

    Change-Id: If20f7a5cef20386e2aeb00cf1d3e283b10da3e93

    Add GetLastCharacterIndex().

    This returns the last character indices when the input text is rendered with the layout size.

    Change-Id: I9f6ff3226a3aeb94c19d3ad69aabc8e017f99cbe

    add minLineSize at text-utils-devel

    Change-Id: I1a11d35283b8f7b4cf14b0ae40487307b24e0a0a

    There is a problem that ellipsis does not work properly when MIN_LINE_SIZE is set.

    Update the penY value.

    Change-Id: Iaab2f2590bda4c80316262dcf4f9fcb0f5a91343

    If the size of the text is larger than the size of the control,
    setting it to VerticalAlignment::Center cuts the top and bottom of the text.

    The VerticalAlignment::CENTER setting works when the size of the control is enough.

    Change-Id: I3d35b4dfceb4297c89bddfc5c5364de4be5bc646

    add Padding parameter at RendererParameters

    Change-Id: If8d78e1363bc02b5f872119af59f6d3b89550b90

Change-Id: Ib96012d9671bbb0154cec76c7800f03590183a41

text tiling

If the length of text is very long and exceeds maxTextureSize,
it cannot be displayed on the screen.

So tiling is required.
I implement tiling by attaching multiple renderers.

And the MAX_TEXT_LENGTH limit is removed.

sample)

    std::ifstream file;
    file.open(PATH[0]);
    std::stringstream ss;
    ss << file.rdbuf();
    file.close();

    ScrollView scroller = ScrollView::New();
    scroller.SetPosition( 100.f, 100.f);
    scroller.SetSize(500.f, 1000.f);
    scroller.SetAnchorPoint(AnchorPoint::TOP_LEFT);
    scroller.SetParentOrigin(ParentOrigin::TOP_LEFT);
    scroller.SetAxisAutoLock(true);

    TextLabel textLabel = TextLabel::New( );
    textLabel.SetProperty( TextLabel::Property::TEXT,  ss.str() );
    textLabel.SetAnchorPoint( AnchorPoint::TOP_LEFT );
    textLabel.SetParentOrigin(ParentOrigin::TOP_LEFT);
    textLabel.SetProperty( TextLabel::Property::VERTICAL_ALIGNMENT, "TOP" );
    textLabel.SetProperty( TextLabel::Property::MULTI_LINE, true );
    textLabel.SetProperty( TextLabel::Property::ELLIPSIS, false );
    textLabel.SetProperty( TextLabel::Property::ENABLE_MARKUP, true );
    textLabel.SetProperty( TextLabel::Property::POINT_SIZE, 16);
    textLabel.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, Color::BLUE );

    scroller.Add( textLabel );
    stage.Add( scroller );

Change-Id: I65082244a801ba697fd9ab0b598c82e702c2a948

14 files changed:
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Controller.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
dali-toolkit/devel-api/controls/text-controls/text-label-devel.h
dali-toolkit/devel-api/text/text-utils-devel.cpp
dali-toolkit/devel-api/text/text-utils-devel.h
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/text/layouts/layout-engine.cpp
dali-toolkit/internal/text/layouts/layout-engine.h
dali-toolkit/internal/text/rendering/text-typesetter.cpp
dali-toolkit/internal/text/shaper.cpp [changed mode: 0644->0755]
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-controller.h
dali-toolkit/internal/visuals/text/text-visual.cpp
dali-toolkit/internal/visuals/text/text-visual.h [changed mode: 0644->0755]

index 064f663..3e53b67 100755 (executable)
@@ -1151,65 +1151,6 @@ int UtcDaliTextControllerSelectEvent(void)
 }
 
 
-int UtcDaliTextControllerMaxLengthSetText(void)
-{
-  tet_infoline(" UtcDaliTextControllerMaxLengthSetText");
-  ToolkitTestApplication application;
-
-  // Creates a text controller.
-  ControllerPtr controller = Controller::New();
-
-  ConfigureTextLabel(controller);
-
-  const Length MAX_TEXT_LENGTH = 1024u * 32u;
-
-  // make over length world
-  int maxLength = (1024u * 32u) + 10u;
-  char world[maxLength];
-  for( int i = 0; i < maxLength; i++ )
-  {
-    world[i] = 'a';
-  }
-
-  // Set the text
-  std::string text(world);
-  controller->SetText( text );
-
-  // Perform a relayout
-  const Size size( Dali::Stage::GetCurrent().GetSize() );
-  controller->Relayout(size);
-
-  // check text length
-  controller->GetText( text );
-  Length textSize = text.size();
-
-  DALI_TEST_EQUALS( MAX_TEXT_LENGTH, textSize, TEST_LOCATION );
-
-  END_TEST;
-}
-
-int UtcDaliTextControllerDirectionCoverage(void)
-{
-  tet_infoline(" UtcDaliTextControllerDirectionCoverage");
-  ToolkitTestApplication application;
-
-  // Creates a text controller.
-  ControllerPtr controller = Controller::New();
-
-  ConfigureTextLabel(controller);
-
-  controller->SetMatchSystemLanguageDirection( true );
-  controller->SetLayoutDirection( Dali::LayoutDirection::RIGHT_TO_LEFT );
-
-  // Perform a relayout
-  const Size size( Dali::Stage::GetCurrent().GetSize() );
-  controller->Relayout(size);
-
-  tet_result(TET_PASS);
-
-  END_TEST;
-}
-
 int UtcDaliTextControllerRemoveTextChangeEventData(void)
 {
   tet_infoline(" UtcDaliTextControllerRemoveTextChangeEventData");
index 646cb2b..939ce1c 100755 (executable)
@@ -26,7 +26,9 @@
 #include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
 #include <dali/devel-api/text-abstraction/bitmap-font.h>
 #include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
 #include <dali-toolkit/devel-api/text/bitmap-font.h>
+#include <dali-toolkit/devel-api/text/text-utils-devel.h>
 
 using namespace Dali;
 using namespace Toolkit;
@@ -636,6 +638,11 @@ int UtcDaliToolkitTextLabelSetPropertyP(void)
   label.SetProperty( Actor::Property::LAYOUT_DIRECTION, LayoutDirection::RIGHT_TO_LEFT );
   DALI_TEST_EQUALS( label.GetProperty< int >( Actor::Property::LAYOUT_DIRECTION ), static_cast< int >( LayoutDirection::RIGHT_TO_LEFT ), TEST_LOCATION );
 
+  // Check the line size property
+  DALI_TEST_EQUALS( label.GetProperty<float>( DevelTextLabel::Property::MIN_LINE_SIZE ), 0.0f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  label.SetProperty( DevelTextLabel::Property::MIN_LINE_SIZE, 50.f );
+  DALI_TEST_EQUALS( label.GetProperty<float>( DevelTextLabel::Property::MIN_LINE_SIZE ), 50.0f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
   application.SendNotification();
   application.Render();
 
@@ -1580,3 +1587,48 @@ int UtcDaliToolkitTextlabelTextFit(void)
 
   END_TEST;
 }
+
+int UtcDaliToolkitTextlabelMaxTextureSet(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextlabelMaxTextureSet");
+
+  DevelText::BitmapFontDescription fontDescription;
+  fontDescription.name = "Digits";
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0030.png", ":", 200.f, 0.f } );
+
+  TextAbstraction::BitmapFont bitmapFont;
+  DevelText::CreateBitmapFont( fontDescription, bitmapFont );
+
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.GetFontId( bitmapFont );
+
+  TextLabel label = TextLabel::New();
+  label.SetProperty( TextLabel::Property::FONT_FAMILY, "Digits" );
+  label.SetProperty( TextLabel::Property::ENABLE_MARKUP, true );
+  label.SetProperty( TextLabel::Property::TEXT, ":This is a long sample text made to allow max texture size to be exceeded." );
+  label.SetProperty( TextLabel::Property::POINT_SIZE, 200.f );
+  label.SetProperty( TextLabel::Property::MULTI_LINE, true );
+
+  Property::Map underlineMapSet;
+  underlineMapSet.Clear();
+  underlineMapSet.Insert( "enable", true );
+  underlineMapSet.Insert( "color", Color::RED );
+  underlineMapSet.Insert( "height", 1 );
+  label.SetProperty( TextLabel::Property::UNDERLINE, underlineMapSet );
+  label.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, Color::BLUE );
+
+  Stage::GetCurrent().Add( label );
+
+  application.SendNotification();
+  application.Render();
+
+  const int maxTextureSize = Dali::GetMaxTextureSize();
+  // Whether the rendered text is greater than maxTextureSize
+  DALI_TEST_CHECK( label.GetCurrentSize().height > maxTextureSize );
+
+  // Check if the number of renderers is greater than 1.
+  DALI_TEST_CHECK( label.GetRendererCount() > 1u );
+
+  END_TEST;
+}
index 72ad6f8..9190441 100755 (executable)
@@ -140,6 +140,13 @@ namespace Property
      */
     TEXT_FIT,
 
+    /**
+     * @brief Sets the height of the line in points.
+     * @details Name "lineSize", type Property::FLOAT.
+     * @note If the font size is larger than the line size, it works with the font size.
+     */
+    MIN_LINE_SIZE,
+
   };
 
 } // namespace Property
index fae3c10..cf5e573 100755 (executable)
@@ -25,6 +25,7 @@
 #include <dali/integration-api/debug.h>
 #include <dali/devel-api/scripting/enum-helper.h>
 #include <cstring>
+#include <limits>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/bidirectional-support.h>
@@ -91,6 +92,7 @@ const float RAD_135 = Math::PI_2 + Math::PI_4; ///< 135 degrees in radians;
 const float RAD_225 = RAD_135    + Math::PI_2; ///< 225 degrees in radians;
 const float RAD_270 = 3.f * Math::PI_2;        ///< 270 degrees in radians;
 const float RAD_315 = RAD_225    + Math::PI_2; ///< 315 degrees in radians;
+const float MAX_INT = std::numeric_limits<int>::max();
 
 DALI_ENUM_TO_STRING_TABLE_BEGIN( LAYOUT_TYPE )
 DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::Layout, SINGLELINE )
@@ -104,6 +106,37 @@ DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::CircularAlignment, CENTER )
 DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::CircularAlignment, END )
 DALI_ENUM_TO_STRING_TABLE_END( CIRCULAR_ALIGNMENT_TYPE )
 
+struct InternalDataModel
+{
+  InternalDataModel( FontClient& fontClient,
+                     MetricsPtr metrics,
+                     Text::ModelPtr textModel )
+  : fontClient( fontClient ),
+    metrics( metrics ),
+    textModel( textModel ),
+    numberOfCharacters{ 0u },
+    isTextMirrored{ false },
+    numberOfGlyphs{ 0u }
+  {
+      layoutEngine.SetMetrics( metrics );
+  }
+
+  FontClient& fontClient;
+  MetricsPtr metrics;
+  Text::Layout::Engine layoutEngine;             ///< The layout engine.
+  Text::ModelPtr textModel;                      ///< Pointer to the text's model.
+  Vector<ColorBlendingMode> blendingMode;        ///< How embedded items and bitmap font glyphs are blended with color text.
+  Vector<bool> isEmoji;                          ///< Whether the glyph is an emoji.
+
+  Vector<Character> mirroredUtf32Characters;               // The utf32Characters Characters but mirrored if there are RTL text.
+
+  Length numberOfCharacters;                               // The number of characters (not glyphs!).
+  bool isTextMirrored ;                                    // Whether the text has been mirrored.
+
+  Length numberOfGlyphs;
+  Size textLayoutArea;
+};
+
 bool GetLayoutEnumeration(const Property::Value& propertyValue, DevelText::Layout::Type& layout)
 {
   return Scripting::GetEnumerationProperty(propertyValue, LAYOUT_TYPE_TABLE, LAYOUT_TYPE_TABLE_COUNT, layout);
@@ -114,80 +147,37 @@ bool GetCircularAlignmentEnumeration(const Property::Value& propertyValue, Devel
   return Scripting::GetEnumerationProperty(propertyValue, CIRCULAR_ALIGNMENT_TYPE_TABLE, CIRCULAR_ALIGNMENT_TYPE_TABLE_COUNT, circularAlignment);
 }
 
-Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<EmbeddedItemInfo>& embeddedItemLayout )
+void ShapeTextPreprocess( const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters, InternalDataModel& internalDataModel )
 {
-  if( textParameters.text.empty() )
-  {
-    Dali::Devel::PixelBuffer pixelBuffer = Dali::Devel::PixelBuffer::New( textParameters.textWidth,
-                                                                          textParameters.textHeight,
-                                                                          Dali::Pixel::RGBA8888 );
-
-    const unsigned int bufferSize = textParameters.textWidth * textParameters.textHeight * Dali::Pixel::GetBytesPerPixel(Dali::Pixel::RGBA8888);
-    unsigned char* buffer = pixelBuffer.GetBuffer();
-    memset(buffer, 0, bufferSize);
-
-    return pixelBuffer;
-  }
 
   MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
-  FontClient fontClient = FontClient::Get();
-  MetricsPtr metrics;
-  Text::Layout::Engine layoutEngine;             ///< The layout engine.
-  Text::ModelPtr textModel = Text::Model::New(); ///< Pointer to the text's model.
-  Vector<ColorBlendingMode> blendingMode;        ///< How embedded items and bitmap font glyphs are blended with color text.
-  Vector<bool> isEmoji;                          ///< Whether the glyph is an emoji.
-
-  // Use this to access FontClient i.e. to get down-scaled Emoji metrics.
-  metrics = Metrics::New( fontClient );
-  layoutEngine.SetMetrics( metrics );
-
-  TextAbstraction::TextRenderer::Parameters rendererParameters( textModel->mVisualModel->mGlyphs,
-                                                                textModel->mVisualModel->mGlyphPositions,
-                                                                textModel->mVisualModel->mColors,
-                                                                textModel->mVisualModel->mColorIndices,
-                                                                blendingMode,
-                                                                isEmoji );
+  const uint8_t* utf8 = NULL;                              // pointer to the first character of the text (encoded in utf8)
+  Length textSize = 0u;                                    // The length of the utf8 string.
 
-  rendererParameters.width = textParameters.textWidth;
-  rendererParameters.height = textParameters.textHeight;
-  rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888; // @note: At the moment all textures are generated RGBA8888
+  Length& numberOfCharacters = internalDataModel.numberOfCharacters;
+  Vector<Character>& mirroredUtf32Characters = internalDataModel.mirroredUtf32Characters;
+  Text::ModelPtr& textModel = internalDataModel.textModel;
 
   Vector<Character>& utf32Characters = textModel->mLogicalModel->mText;                                             // Characters encoded in utf32.
-  Vector<Character> mirroredUtf32Characters;                                                                        // The utf32Characters Characters but mirrored if there are RTL text.
   Vector<LineBreakInfo>& lineBreakInfo = textModel->mLogicalModel->mLineBreakInfo;                                  // The line break info.
   Vector<ScriptRun>& scripts = textModel->mLogicalModel->mScriptRuns;                                               // Charactes's script.
   Vector<FontDescriptionRun>& fontDescriptionRuns = textModel->mLogicalModel->mFontDescriptionRuns;                 // Desired font descriptions.
   Vector<FontRun>& validFonts = textModel->mLogicalModel->mFontRuns;                                                // Validated fonts.
   Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = textModel->mLogicalModel->mBidirectionalParagraphInfo; // The bidirectional info per paragraph.
-  //Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = textModel->mLogicalModel->mBidirectionalLineInfo;     // The bidirectional info per line.
   Vector<CharacterDirection>& directions = textModel->mLogicalModel->mCharacterDirections;                          // Character's directions.
   Vector<ColorRun>& colorRuns = textModel->mLogicalModel->mColorRuns;                                               // colors of the text.
 
-  Vector<CharacterIndex>& glyphsToCharacters = textModel->mVisualModel->mGlyphsToCharacters;                        // Glyphs to character map.
-  Vector<GlyphIndex>& charactersToGlyph = textModel->mVisualModel->mCharactersToGlyph;                              // Characters to glyphs map.
-  Vector<Length>& charactersPerGlyph = textModel->mVisualModel->mCharactersPerGlyph;                                // Number of characters per glyph.
-  Vector<Length>& glyphsPerCharacter = textModel->mVisualModel->mGlyphsPerCharacter;                                // The number of glyphs that are shaped.
-  Vector<LineRun>& lines = textModel->mVisualModel->mLines;                                                         // The laid out lines.
-
-  Vector<GlyphIndex> newParagraphGlyphs;                   // Glyphs for the new paragraph characters.
-
   // the default font's description.
   FontDescription defaultFontDescription;
   PointSize26Dot6 defaultPointSize = FontClient::DEFAULT_POINT_SIZE;
 
-  Length numberOfCharacters = 0u;                          // The number of characters (not glyphs!).
-  bool isTextMirrored = false;                             // Whether the text has been mirrored.
-
-  const uint8_t* utf8 = NULL;                              // pointer to the first character of the text (encoded in utf8)
-  Length textSize = 0u;                                    // The length of the utf8 string.
-
   ////////////////////////////////////////////////////////////////////////////////
   // Process the markup string if the mark-up processor is enabled.
   ////////////////////////////////////////////////////////////////////////////////
 
   MarkupProcessData markupProcessData( colorRuns,
-                                       fontDescriptionRuns,
-                                       textModel->mLogicalModel->mEmbeddedItems );
+                                      fontDescriptionRuns,
+                                      textModel->mLogicalModel->mEmbeddedItems );
 
   if (textParameters.markupEnabled)
   {
@@ -232,9 +222,9 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
   ////////////////////////////////////////////////////////////////////////////////
 
   multilanguageSupport.SetScripts( utf32Characters,
-                                   0u,
-                                   numberOfCharacters,
-                                   scripts );
+                                  0u,
+                                  numberOfCharacters,
+                                  scripts );
 
   // Check if there are emojis.
   // If there are an RGBA8888 pixel format is needed.
@@ -330,13 +320,30 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
     // This paragraph has right to left text. Some characters may need to be mirrored.
     // TODO: consider if the mirrored string can be stored as well.
 
-    isTextMirrored = GetMirroredText( utf32Characters,
+    internalDataModel.isTextMirrored = GetMirroredText( utf32Characters,
                                       directions,
                                       bidirectionalInfo,
                                       0u,
                                       numberOfCharacters,
                                       mirroredUtf32Characters );
   }
+}
+
+void ShapeText( TextAbstraction::TextRenderer::Parameters& rendererParameters, Vector<EmbeddedItemInfo>& embeddedItemLayout, InternalDataModel& internalDataModel )
+{
+  Vector<GlyphIndex> newParagraphGlyphs;                   // Glyphs for the new paragraph characters.
+  const Length numberOfCharacters = internalDataModel.numberOfCharacters;
+  const bool isTextMirrored = internalDataModel.isTextMirrored;
+  Text::ModelPtr& textModel = internalDataModel.textModel;
+  const Vector<Character>& mirroredUtf32Characters = internalDataModel.mirroredUtf32Characters;
+  FontClient& fontClient = internalDataModel.fontClient;
+  const Vector<Character>& utf32Characters = textModel->mLogicalModel->mText;                                             // Characters encoded in utf32.
+  const Vector<LineBreakInfo>& lineBreakInfo = textModel->mLogicalModel->mLineBreakInfo;                                  // The line break info.
+  const Vector<ScriptRun>& scripts = textModel->mLogicalModel->mScriptRuns;                                               // Charactes's script.
+  const Vector<FontRun>& validFonts = textModel->mLogicalModel->mFontRuns;                                                // Validated fonts.
+
+  Vector<CharacterIndex>& glyphsToCharacters = textModel->mVisualModel->mGlyphsToCharacters;                        // Glyphs to character map.
+  Vector<Length>& charactersPerGlyph = textModel->mVisualModel->mCharactersPerGlyph;                                // Number of characters per glyph.
 
   ////////////////////////////////////////////////////////////////////////////////
   // Retrieve the glyphs. Text shaping
@@ -363,7 +370,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
   textModel->mVisualModel->CreateGlyphsPerCharacterTable( 0u, 0u, numberOfCharacters );
   textModel->mVisualModel->CreateCharacterToGlyphTable( 0u, 0u, numberOfCharacters );
 
-  const Length numberOfGlyphs = rendererParameters.glyphs.Count();
+  internalDataModel.numberOfGlyphs = rendererParameters.glyphs.Count();
 
   // Once the text has been shaped and the glyphs created it's possible to replace the font id of those glyphs
   // that represent an image or an item and create the embedded item layout info.
@@ -402,12 +409,18 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
       embeddedItemLayout.PushBack( embeddedInfo );
     }
   }
+}
 
-  ////////////////////////////////////////////////////////////////////////////////
-  // Retrieve the glyph's metrics.
-  ////////////////////////////////////////////////////////////////////////////////
+void SetColorSegmentation( const RendererParameters& textParameters, InternalDataModel& internalDataModel )
+{
 
-  metrics->GetGlyphMetrics( rendererParameters.glyphs.Begin(), numberOfGlyphs );
+  Text::ModelPtr& textModel = internalDataModel.textModel;
+  Vector<ColorBlendingMode>& blendingMode = internalDataModel.blendingMode;
+
+  Vector<ColorRun>& colorRuns = textModel->mLogicalModel->mColorRuns;                                               // colors of the text.
+
+  Vector<GlyphIndex>& charactersToGlyph = textModel->mVisualModel->mCharactersToGlyph;                              // Characters to glyphs map.
+  Vector<Length>& glyphsPerCharacter = textModel->mVisualModel->mGlyphsPerCharacter;                                // The number of glyphs that are shaped.
 
   ////////////////////////////////////////////////////////////////////////////////
   // Set the color runs in glyphs.
@@ -418,7 +431,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
                             glyphsPerCharacter,
                             0u,
                             0u,
-                            numberOfCharacters,
+                            internalDataModel.numberOfCharacters,
                             textModel->mVisualModel->mColors,
                             textModel->mVisualModel->mColorIndices );
 
@@ -426,7 +439,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
   textModel->mVisualModel->mColors.Insert( textModel->mVisualModel->mColors.Begin(),textParameters.textColor );
 
   // Set how the embedded items are blended with text color.
-  blendingMode.Resize( numberOfGlyphs, textParameters.isTextColorSet ? ColorBlendingMode::MULTIPLY : ColorBlendingMode::NONE );
+  blendingMode.Resize( internalDataModel.numberOfGlyphs, textParameters.isTextColorSet ? ColorBlendingMode::MULTIPLY : ColorBlendingMode::NONE );
 
   if( !textParameters.isTextColorSet )
   {
@@ -450,7 +463,15 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
     const GlyphIndex glyphIndex = textModel->mVisualModel->mCharactersToGlyph[item.characterIndex];
     blendingMode[glyphIndex] = item.colorBlendingMode;
   }
+}
+
+void SetEmojiVector( InternalDataModel& internalDataModel )
+{
+  Vector<bool>& isEmoji = internalDataModel.isEmoji;
+  Text::ModelPtr& textModel = internalDataModel.textModel;
+  const Length numberOfGlyphs = internalDataModel.numberOfGlyphs;
 
+  const Vector<ScriptRun>& scripts = textModel->mLogicalModel->mScriptRuns;                                               // Charactes's script.
   ////////////////////////////////////////////////////////////////////////////////
   // Set the isEmoji Vector
   ////////////////////////////////////////////////////////////////////////////////
@@ -471,18 +492,32 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
       }
     }
   }
+}
+
+
+void Align( const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters,
+            Vector<EmbeddedItemInfo>& embeddedItemLayout, InternalDataModel& internalDataModel,
+            const Size& newLayoutSize )
+{
+  Text::Layout::Engine& layoutEngine = internalDataModel.layoutEngine;
+  Text::ModelPtr& textModel = internalDataModel.textModel;
+  const Length numberOfCharacters = internalDataModel.numberOfCharacters;
+  Size& textLayoutArea = internalDataModel.textLayoutArea;
+
+  Vector<LineRun>& lines = textModel->mVisualModel->mLines;                                                         // The laid out lines.
 
   ////////////////////////////////////////////////////////////////////////////////
-  // Layout the text.
+  // Align the text.
   ////////////////////////////////////////////////////////////////////////////////
 
-  // Sets the alignment
   HorizontalAlignment::Type horizontalAlignment = Toolkit::HorizontalAlignment::CENTER;
   HorizontalAlignment::Type horizontalCircularAlignment = Toolkit::HorizontalAlignment::CENTER;
   VerticalAlignment::Type verticalAlignment = VerticalAlignment::CENTER;
-  Layout::Type layout = Layout::SINGLELINE;
   CircularAlignment::Type circularAlignment = CircularAlignment::BEGIN;
 
+  Layout::Type layout = Layout::SINGLELINE;
+
+  // Sets the alignment
   Property::Value horizontalAlignmentStr( textParameters.horizontalAlignment );
   GetHorizontalAlignmentEnumeration( horizontalAlignmentStr, horizontalAlignment );
   horizontalCircularAlignment = horizontalAlignment;
@@ -490,40 +525,16 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
   Property::Value verticalAlignmentStr( textParameters.verticalAlignment );
   GetVerticalAlignmentEnumeration( verticalAlignmentStr, verticalAlignment );
 
-  Property::Value layoutStr( textParameters.layout );
-  GetLayoutEnumeration( layoutStr, layout );
-
   Property::Value circularAlignmentStr( textParameters.circularAlignment );
   GetCircularAlignmentEnumeration( circularAlignmentStr, circularAlignment );
 
-  // Whether the layout is multi-line.
-  const Text::Layout::Engine::Type horizontalLayout = ( Layout::MULTILINE == layout ) ? Text::Layout::Engine::MULTI_LINE_BOX : Text::Layout::Engine::SINGLE_LINE_BOX;
-  layoutEngine.SetLayout( horizontalLayout ); // TODO: multi-line.
-
+  Property::Value layoutStr( textParameters.layout );
+  GetLayoutEnumeration( layoutStr, layout );
 
   // Whether the layout is circular.
   const bool isCircularTextLayout = (Layout::CIRCULAR == layout);
   const bool isClockwise = isCircularTextLayout && ( 0.f < textParameters.incrementAngle );
 
-  // Calculates the max ascender or the max descender.
-  // Is used to calculate the radius of the base line of the text.
-  float maxAscenderDescender = 0.f;
-  if( isCircularTextLayout )
-  {
-    FontId currentFontId = 0u;
-    for( const auto& glyph : rendererParameters.glyphs )
-    {
-      if( currentFontId != glyph.fontId )
-      {
-        currentFontId = glyph.fontId;
-        FontMetrics metrics;
-        fontClient.GetFontMetrics(currentFontId, metrics);
-        maxAscenderDescender = std::max( maxAscenderDescender, isClockwise ? metrics.ascender : metrics.descender );
-      }
-    }
-  }
-  const unsigned int radius = textParameters.radius - static_cast<unsigned int>( maxAscenderDescender );
-
   // Convert CircularAlignment to HorizontalAlignment.
   if( isCircularTextLayout )
   {
@@ -546,49 +557,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
       }
     }
   }
-
-  // Set the layout parameters.
-  Size textLayoutArea( static_cast<float>( textParameters.textWidth ),
-                     static_cast<float>( textParameters.textHeight ) );
-
-  if( isCircularTextLayout )
-  {
-    // In a circular layout, the length of the text area depends on the radius.
-    rendererParameters.radius = radius;
-    textLayoutArea.width = fabs( Radian( Degree( textParameters.incrementAngle ) ) * static_cast<float>( rendererParameters.radius ) );
-  }
-
   textModel->mHorizontalAlignment = isCircularTextLayout ? horizontalCircularAlignment : horizontalAlignment;
-  textModel->mLineWrapMode = LineWrap::WORD;
-  textModel->mIgnoreSpacesAfterText = false;
-  textModel->mMatchSystemLanguageDirection = false;
-  Text::Layout::Parameters layoutParameters( textLayoutArea,
-                                             textModel );
-
-  // Resize the vector of positions to have the same size than the vector of glyphs.
-  rendererParameters.positions.Resize( numberOfGlyphs );
-
-  // Whether the last character is a new paragraph character.
-  layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( textToShape[numberOfCharacters - 1u] );
-
-  // The initial glyph and the number of glyphs to layout.
-  layoutParameters.startGlyphIndex = 0u;
-  layoutParameters.numberOfGlyphs = numberOfGlyphs;
-  layoutParameters.startLineIndex = 0u;
-  layoutParameters.estimatedNumberOfLines = 1u;
-  layoutParameters.interGlyphExtraAdvance = 0.f;
-
-  // Update the visual model.
-  Size newLayoutSize;
-  bool isAutoScrollEnabled = false;
-  layoutEngine.LayoutText( layoutParameters,
-                           newLayoutSize,
-                           textParameters.ellipsisEnabled,
-                           isAutoScrollEnabled );
-
-  ////////////////////////////////////////////////////////////////////////////////
-  // Align the text.
-  ////////////////////////////////////////////////////////////////////////////////
 
   // Retrieve the line of text to know the direction and the width. @todo multi-line
   const LineRun& line = lines[0u];
@@ -684,14 +653,14 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
       {
         const bool isNeg = textParameters.incrementAngle < 0.f;
         const float textWidth = static_cast<float>( rendererParameters.circularWidth );
-        angleOffset = ( isNeg ? -0.5f : 0.5f ) * ( textLayoutArea.width - textWidth ) / static_cast<float>( radius );
+        angleOffset = ( isNeg ? -0.5f : 0.5f ) * ( textLayoutArea.width - textWidth ) / static_cast<float>( rendererParameters.radius );
         break;
       }
       case CircularAlignment::END:
       {
         const bool isNeg = textParameters.incrementAngle < 0.f;
         const float textWidth = static_cast<float>( rendererParameters.circularWidth );
-        angleOffset = ( isNeg ? -1.f : 1.f ) * ( textLayoutArea.width - textWidth ) / static_cast<float>( radius );
+        angleOffset = ( isNeg ? -1.f : 1.f ) * ( textLayoutArea.width - textWidth ) / static_cast<float>( rendererParameters.radius );
         break;
       }
     }
@@ -730,7 +699,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
     }
 
     // Calculate the horizontal offset according with the given alignment.
-  float alignmentOffset = 0.f;
+    float alignmentOffset = 0.f;
     layoutEngine.Align( textLayoutArea,
                       0u,
                       numberOfCharacters,
@@ -742,10 +711,10 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
 
     // Update the position of the glyphs with the calculated offsets.
     for( auto& position : rendererParameters.positions )
-  {
-    position.x += line.alignmentOffset;
-    position.y = penY;
-  }
+    {
+      position.x += line.alignmentOffset;
+      position.y = penY;
+    }
   }
 
   // Cairo adds the bearing to the position of the glyph
@@ -780,7 +749,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
 
       Dali::TextAbstraction::CircularTextParameters circularTextParameters;
 
-      circularTextParameters.radius = static_cast<double>( radius );
+      circularTextParameters.radius = static_cast<double>( rendererParameters.radius );
       circularTextParameters.invRadius = 1.0 / circularTextParameters.radius;
       circularTextParameters.beginAngle = static_cast<double>( -rendererParameters.beginAngle + Dali::Math::PI_2 );
       circularTextParameters.centerX = 0.5f * static_cast<double>( textParameters.textWidth );
@@ -845,6 +814,17 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
     }
   }
 
+}
+
+void Ellipsis(  const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters,
+               Vector<EmbeddedItemInfo>& embeddedItemLayout, InternalDataModel& internalDataModel )
+{
+  Text::ModelPtr& textModel = internalDataModel.textModel;
+  FontClient& fontClient = internalDataModel.fontClient;
+
+  Vector<LineRun>& lines = textModel->mVisualModel->mLines;                              // The laid out lines.
+  Vector<bool>& isEmoji = internalDataModel.isEmoji;
+  const Size textLayoutArea = internalDataModel.textLayoutArea;
   ////////////////////////////////////////////////////////////////////////////////
   // Ellipsis the text.
   ////////////////////////////////////////////////////////////////////////////////
@@ -995,7 +975,108 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
       }
     }
   }
+}
 
+Size LayoutText( const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters,
+                 Vector<EmbeddedItemInfo>& embeddedItemLayout, InternalDataModel& internalDataModel )
+{
+  ////////////////////////////////////////////////////////////////////////////////
+  // Layout the text.
+  ////////////////////////////////////////////////////////////////////////////////
+  Text::ModelPtr& textModel = internalDataModel.textModel;
+  Text::Layout::Engine& layoutEngine = internalDataModel.layoutEngine;
+  FontClient& fontClient = internalDataModel.fontClient;
+  const Length numberOfGlyphs = internalDataModel.numberOfGlyphs;
+  const bool isTextMirrored = internalDataModel.isTextMirrored;
+  const Vector<Character>& mirroredUtf32Characters = internalDataModel.mirroredUtf32Characters;
+  const Length numberOfCharacters = internalDataModel.numberOfCharacters;
+
+  Layout::Type layout = Layout::SINGLELINE;
+
+  Property::Value layoutStr( textParameters.layout );
+  GetLayoutEnumeration( layoutStr, layout );
+
+  // Whether the layout is multi-line.
+  const Text::Layout::Engine::Type horizontalLayout = ( Layout::MULTILINE == layout ) ? Text::Layout::Engine::MULTI_LINE_BOX : Text::Layout::Engine::SINGLE_LINE_BOX;
+  layoutEngine.SetLayout( horizontalLayout ); // TODO: multi-line.
+
+  // Set minimun line size
+  layoutEngine.SetDefaultLineSize( textParameters.minLineSize );
+
+  // Whether the layout is circular.
+  const bool isCircularTextLayout = (Layout::CIRCULAR == layout);
+  const bool isClockwise = isCircularTextLayout && ( 0.f < textParameters.incrementAngle );
+
+  // Calculates the max ascender or the max descender.
+  // Is used to calculate the radius of the base line of the text.
+  float maxAscenderDescender = 0.f;
+  if( isCircularTextLayout )
+  {
+    FontId currentFontId = 0u;
+    for( const auto& glyph : rendererParameters.glyphs )
+    {
+      if( currentFontId != glyph.fontId )
+      {
+        currentFontId = glyph.fontId;
+        FontMetrics metrics;
+        fontClient.GetFontMetrics(currentFontId, metrics);
+        maxAscenderDescender = std::max( maxAscenderDescender, isClockwise ? metrics.ascender : metrics.descender );
+      }
+    }
+  }
+  const unsigned int radius = textParameters.radius - static_cast<unsigned int>( maxAscenderDescender );
+
+  // Set the layout parameters.
+  Size textLayoutArea = Size(static_cast<float>(textParameters.textWidth),
+                                          static_cast<float>(textParameters.textHeight));
+
+  // padding
+  Extents padding = textParameters.padding;
+  internalDataModel.textLayoutArea = Size(textLayoutArea.x - ( padding.start + padding.end ), textLayoutArea.y - ( padding.top + padding.bottom ) );
+
+
+  if(isCircularTextLayout)
+  {
+    // In a circular layout, the length of the text area depends on the radius.
+    rendererParameters.radius = radius;
+    internalDataModel.textLayoutArea.width = fabs( Radian( Degree( textParameters.incrementAngle ) ) * static_cast<float>( rendererParameters.radius ) );
+  }
+  // Resize the vector of positions to have the same size than the vector of glyphs.
+  rendererParameters.positions.Resize( numberOfGlyphs );
+
+  textModel->mLineWrapMode = LineWrap::WORD;
+  textModel->mIgnoreSpacesAfterText = false;
+  textModel->mMatchSystemLanguageDirection = false;
+  Text::Layout::Parameters layoutParameters( internalDataModel.textLayoutArea,
+                                             textModel );
+
+
+  // Whether the last character is a new paragraph character.
+  const Vector<Character>& textToShape = isTextMirrored ? mirroredUtf32Characters : textModel->mLogicalModel->mText;
+  layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( textToShape[numberOfCharacters - 1u] );
+
+  // The initial glyph and the number of glyphs to layout.
+  layoutParameters.startGlyphIndex = 0u;
+  layoutParameters.numberOfGlyphs = numberOfGlyphs;
+  layoutParameters.startLineIndex = 0u;
+  layoutParameters.estimatedNumberOfLines = 1u;
+  layoutParameters.interGlyphExtraAdvance = 0.f;
+
+  // Update the visual model.
+  Size newLayoutSize;
+  bool isAutoScrollEnabled = false;
+  layoutEngine.LayoutText( layoutParameters,
+                           newLayoutSize,
+                           textParameters.ellipsisEnabled,
+                           isAutoScrollEnabled );
+
+  return newLayoutSize;
+
+}
+
+
+Devel::PixelBuffer RenderText( const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters )
+{
   ////////////////////////////////////////////////////////////////////////////////
   // Render the text.
   ////////////////////////////////////////////////////////////////////////////////
@@ -1007,6 +1088,94 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
   return renderer.Render( rendererParameters );
 }
 
+
+Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<EmbeddedItemInfo>& embeddedItemLayout )
+{
+  if( textParameters.text.empty() )
+  {
+    Dali::Devel::PixelBuffer pixelBuffer = Dali::Devel::PixelBuffer::New( textParameters.textWidth,
+                                                                          textParameters.textHeight,
+                                                                          Dali::Pixel::RGBA8888 );
+
+    const unsigned int bufferSize = textParameters.textWidth * textParameters.textHeight * Dali::Pixel::GetBytesPerPixel(Dali::Pixel::RGBA8888);
+    unsigned char* buffer = pixelBuffer.GetBuffer();
+    memset(buffer, 0, bufferSize);
+
+    return pixelBuffer;
+  }
+
+  FontClient fontClient = FontClient::Get();
+  MetricsPtr metrics;
+  // Use this to access FontClient i.e. to get down-scaled Emoji metrics.
+  metrics = Metrics::New( fontClient );
+
+  Text::ModelPtr textModel = Text::Model::New();
+  InternalDataModel internalData( fontClient, metrics, textModel );
+
+  TextAbstraction::TextRenderer::Parameters rendererParameters( internalData.textModel->mVisualModel->mGlyphs,
+                                                                internalData.textModel->mVisualModel->mGlyphPositions,
+                                                                internalData.textModel->mVisualModel->mColors,
+                                                                internalData.textModel->mVisualModel->mColorIndices,
+                                                                internalData.blendingMode,
+                                                                internalData.isEmoji );
+
+
+  rendererParameters.width = textParameters.textWidth;
+  rendererParameters.height = textParameters.textHeight;
+  rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888; // @note: At the moment all textures are generated RGBA8888
+
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Process the markup string if the mark-up processor is enabled.
+  ////////////////////////////////////////////////////////////////////////////////
+  ShapeTextPreprocess( textParameters, rendererParameters, internalData );
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Retrieve the glyphs. Text shaping
+  ////////////////////////////////////////////////////////////////////////////////
+  ShapeText( rendererParameters, embeddedItemLayout, internalData );
+
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Retrieve the glyph's metrics.
+  ////////////////////////////////////////////////////////////////////////////////
+
+  metrics->GetGlyphMetrics( rendererParameters.glyphs.Begin(), internalData.numberOfGlyphs );
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Set the color runs in glyphs.
+  ////////////////////////////////////////////////////////////////////////////////
+  SetColorSegmentation( textParameters, internalData );
+
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Set the isEmoji Vector
+  ////////////////////////////////////////////////////////////////////////////////
+  SetEmojiVector( internalData );
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Layout the text
+  ////////////////////////////////////////////////////////////////////////////////
+  Size newLayoutSize = LayoutText( textParameters, rendererParameters, embeddedItemLayout, internalData );
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Align the text.
+  ////////////////////////////////////////////////////////////////////////////////
+  Align( textParameters, rendererParameters, embeddedItemLayout, internalData, newLayoutSize );
+
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Ellipsis the text.
+  ////////////////////////////////////////////////////////////////////////////////
+  Ellipsis( textParameters, rendererParameters, embeddedItemLayout, internalData );
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Render the text.
+  ////////////////////////////////////////////////////////////////////////////////
+  return RenderText( textParameters, rendererParameters );
+}
+
+
 Devel::PixelBuffer CreateShadow( const ShadowParameters& shadowParameters )
 {
   // The size of the pixel data.
@@ -1316,6 +1485,96 @@ void UpdateBuffer(Devel::PixelBuffer src, Devel::PixelBuffer dst, unsigned int x
   }
 }
 
+
+Dali::Property::Array RenderForLastIndex( RendererParameters& textParameters )
+{
+  Property::Array offsetValues;
+  if( textParameters.text.empty() )
+  {
+    return offsetValues;
+  }
+  FontClient fontClient = FontClient::Get();
+  MetricsPtr metrics;
+  metrics = Metrics::New( fontClient );
+
+  Text::ModelPtr textModel = Text::Model::New();
+  InternalDataModel internalData( fontClient, metrics, textModel );
+
+  TextAbstraction::TextRenderer::Parameters rendererParameters( textModel->mVisualModel->mGlyphs,
+                                                                textModel->mVisualModel->mGlyphPositions,
+                                                                textModel->mVisualModel->mColors,
+                                                                textModel->mVisualModel->mColorIndices,
+                                                                internalData.blendingMode,
+                                                                internalData.isEmoji );
+
+
+  rendererParameters.width = textParameters.textWidth;
+  rendererParameters.height = textParameters.textHeight;
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Process the markup string if the mark-up processor is enabled.
+  ////////////////////////////////////////////////////////////////////////////////
+  ShapeTextPreprocess( textParameters, rendererParameters, internalData );
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Retrieve the glyphs. Text shaping
+  ////////////////////////////////////////////////////////////////////////////////
+  Dali::Vector<Dali::Toolkit::DevelText::EmbeddedItemInfo> embeddedItemLayout;
+  ShapeText( rendererParameters, embeddedItemLayout, internalData );
+
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Retrieve the glyph's metrics.
+  ////////////////////////////////////////////////////////////////////////////////
+  metrics->GetGlyphMetrics( rendererParameters.glyphs.Begin(), internalData.numberOfGlyphs );
+
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Layout the text
+  ////////////////////////////////////////////////////////////////////////////////
+  int boundingBox           = textParameters.textHeight - (textParameters.padding.top + textParameters.padding.bottom);
+  textParameters.textHeight = MAX_INT; // layout for the entire area.
+  LayoutText( textParameters, rendererParameters, embeddedItemLayout, internalData );
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Calculation last character index
+  ////////////////////////////////////////////////////////////////////////////////
+  Vector<LineRun>& lines = internalData.textModel->mVisualModel->mLines;
+  unsigned int numberOfLines = lines.Count();
+  int numberOfCharacters = 0;
+  float penY = 0.f;
+  float lineSize = internalData.layoutEngine.GetDefaultLineSize();
+  float lineOffset = 0.f;
+  for( unsigned int index = 0u; index < numberOfLines; ++index  )
+  {
+    const LineRun& line = *( lines.Begin() + index );
+    numberOfCharacters += line.characterRun.numberOfCharacters;
+
+    lineOffset = lineSize > 0.f ? lineSize : ( line.ascender + -line.descender );
+    penY += lineOffset;
+    if( ( penY + lineOffset ) > boundingBox )
+    {
+      offsetValues.PushBack( numberOfCharacters );
+      penY = 0.f;
+    }
+  }
+  if( penY > 0.f)
+  {
+    // add remain character index
+    offsetValues.PushBack( numberOfCharacters );
+  }
+
+  return offsetValues;
+}
+
+
+Dali::Property::Array GetLastCharacterIndex( RendererParameters& textParameters )
+{
+  Dali::Property::Array offsetValues = Toolkit::DevelText::RenderForLastIndex( textParameters );
+  return offsetValues;
+}
+
+
 } // namespace DevelText
 
 } // namespace Toolkit
index 83c6ea9..86c44e8 100755 (executable)
@@ -19,6 +19,7 @@
  */
 
 // EXTERNAL INCLUDES
+#include <dali/public-api/object/property-array.h>
 #include <dali-toolkit/public-api/dali-toolkit-common.h>
 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
 #include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
@@ -45,19 +46,22 @@ struct DALI_TOOLKIT_API RendererParameters
     fontWeight{},
     fontWidth{},
     fontSlant{},
-    layout{ "singleLine" },
-    circularAlignment{ "begin" },
-    textColor{ Color::WHITE },
-    fontSize{ 0.f },
-    textWidth{ 0u },
-    textHeight{ 0u },
-    radius{ 0u },
-    beginAngle{ 0.f },
-    incrementAngle{ 0.f },
-    ellipsisEnabled{ true },
-    markupEnabled{ false },
-    isTextColorSet{ false }
-  {}
+    layout{"singleLine"},
+    circularAlignment{"begin"},
+    textColor{Color::WHITE},
+    fontSize{0.f},
+    textWidth{0u},
+    textHeight{0u},
+    radius{0u},
+    beginAngle{0.f},
+    incrementAngle{0.f},
+    ellipsisEnabled{true},
+    markupEnabled{false},
+    isTextColorSet{false},
+    minLineSize{0.f},
+    padding{0u, 0u, 0u, 0u}
+  {
+  }
 
   std::string text;                ///< The text to be rendered encoded in utf8.
 
@@ -85,6 +89,10 @@ struct DALI_TOOLKIT_API RendererParameters
   bool ellipsisEnabled:1;          ///< Whether the ellipsis layout option is enabled.
   bool markupEnabled:1;            ///< Whether the mark-up processor is enabled.
   bool isTextColorSet:1;           ///< Whether a default color has been set.
+
+  float minLineSize;               ///< The line's minimum size (in points).
+
+  Extents padding;                 ///< The padding of the boundaries where the text is going to be laid-out.
 };
 
 /**
@@ -192,6 +200,14 @@ DALI_TOOLKIT_API Devel::PixelBuffer ConvertToRgba8888( Devel::PixelBuffer pixelB
 */
 DALI_TOOLKIT_API void UpdateBuffer( Devel::PixelBuffer src, Devel::PixelBuffer dst, unsigned int x, unsigned int y, bool blend);
 
+/**
+ * @brief Splits the text in pages of the size given in @p textParameters
+ *
+ * @note The returned indices are indices to utf32 characters. The input text is encoded in utf8.
+ * @return An array with the indices of the last character of each page
+ */
+DALI_TOOLKIT_API Dali::Property::Array GetLastCharacterIndex( RendererParameters& textParameters );
+
 } // namespace DevelText
 
 } // namespace Toolkit
index 73f383f..4c3402d 100755 (executable)
@@ -140,7 +140,8 @@ DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit,     TextLabel, "verticalLineAlignment
 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit,     TextLabel, "textBackground",            MAP,     BACKGROUND                 )
 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit,     TextLabel, "ignoreSpacesAfterText",     BOOLEAN, IGNORE_SPACES_AFTER_TEXT   )
 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit,     TextLabel, "matchSystemLanguageDirection", BOOLEAN, MATCH_SYSTEM_LANGUAGE_DIRECTION )
-DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit,     TextLabel, "textFit",                   MAP,     TEXT_FIT                 )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit,     TextLabel, "textFit",                   MAP,     TEXT_FIT                   )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit,     TextLabel, "minLineSize",               FLOAT,   MIN_LINE_SIZE              )
 DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( Toolkit, TextLabel, "textColor",      Color::BLACK,     TEXT_COLOR     )
 DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit,    TextLabel, "textColorRed",   TEXT_COLOR_RED,   TEXT_COLOR, 0  )
 DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit,    TextLabel, "textColorGreen", TEXT_COLOR_GREEN, TEXT_COLOR, 1  )
@@ -553,6 +554,19 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
         }
         break;
       }
+      case Toolkit::DevelTextLabel::Property::MIN_LINE_SIZE:
+      {
+        if( impl.mController )
+        {
+          const float lineSize = value.Get<float>();
+
+          if( impl.mController->SetDefaultLineSize( lineSize ) )
+          {
+            impl.mTextUpdateNeeded = true;
+          }
+        }
+        break;
+      }
     }
 
     // Request relayout when text update is needed. It's necessary to call it
@@ -834,6 +848,14 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde
         value = map;
         break;
       }
+      case Toolkit::DevelTextLabel::Property::MIN_LINE_SIZE:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetDefaultLineSize();
+        }
+        break;
+      }
     }
   }
 
index 4246f96..3bd4568 100755 (executable)
@@ -52,7 +52,8 @@ namespace
 const float MAX_FLOAT = std::numeric_limits<float>::max();
 const CharacterDirection LTR = false;
 const CharacterDirection RTL = !LTR;
-const float LINE_SPACING= 0.f;
+const float LINE_SPACING = 0.f;
+const float MIN_LINE_SIZE = 0.f;
 
 inline bool isEmptyLineAtLast( const Vector<LineRun>& lines, const Vector<LineRun>::Iterator& line )
 {
@@ -130,7 +131,8 @@ struct Engine::Impl
   Impl()
   : mLayout{ Layout::Engine::SINGLE_LINE_BOX },
     mCursorWidth{ 0.f },
-    mDefaultLineSpacing{ LINE_SPACING }
+    mDefaultLineSpacing{ LINE_SPACING },
+    mDefaultLineSize{ MIN_LINE_SIZE }
   {
   }
 
@@ -162,8 +164,12 @@ struct Engine::Impl
     // Sets the minimum descender.
     lineLayout.descender = std::min( lineLayout.descender, fontMetrics.descender );
 
-    // set the line spacing
-    lineLayout.lineSpacing = mDefaultLineSpacing;
+    // Sets the line size
+    lineLayout.lineSpacing = mDefaultLineSize - ( lineLayout.ascender + -lineLayout.descender );
+    lineLayout.lineSpacing = lineLayout.lineSpacing < 0.f ? 0.f : lineLayout.lineSpacing;
+
+    // Add the line spacing
+    lineLayout.lineSpacing += mDefaultLineSpacing;
   }
 
   /**
@@ -921,8 +927,6 @@ struct Engine::Impl
     lineRun.glyphRun.numberOfGlyphs = layout.numberOfGlyphs;
     lineRun.characterRun.characterIndex = layout.characterIndex;
     lineRun.characterRun.numberOfCharacters = layout.numberOfCharacters;
-    lineRun.lineSpacing = mDefaultLineSpacing;
-
     lineRun.width = layout.length;
     lineRun.extraLength = std::ceil( layout.whiteSpaceLengthEndOfLine );
 
@@ -935,6 +939,12 @@ struct Engine::Impl
     lineRun.direction = layout.direction;
     lineRun.ellipsis = false;
 
+    lineRun.lineSpacing = mDefaultLineSize - ( lineRun.ascender + -lineRun.descender );
+    lineRun.lineSpacing = lineRun.lineSpacing < 0.f ? 0.f : lineRun.lineSpacing;
+
+    lineRun.lineSpacing += mDefaultLineSpacing;
+
+
     // Update the actual size.
     if( lineRun.width > layoutSize.width )
     {
@@ -986,7 +996,11 @@ struct Engine::Impl
     lineRun.alignmentOffset = 0.f;
     lineRun.direction = LTR;
     lineRun.ellipsis = false;
-    lineRun.lineSpacing = mDefaultLineSpacing;
+
+    lineRun.lineSpacing = mDefaultLineSize - ( lineRun.ascender + -lineRun.descender );
+    lineRun.lineSpacing = lineRun.lineSpacing < 0.f ? 0.f : lineRun.lineSpacing;
+
+    lineRun.lineSpacing += mDefaultLineSpacing;
 
     layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing;
   }
@@ -1346,6 +1360,13 @@ struct Engine::Impl
 
         // Updates the vertical pen's position.
         penY += -layout.descender + layout.lineSpacing + mDefaultLineSpacing;
+        // If there is a defaultLineSize, updates the pen's position.
+        if( mDefaultLineSize > 0.f )
+        {
+          float lineSpacing = mDefaultLineSize - ( layout.ascender + -layout.descender );
+          lineSpacing = lineSpacing < 0.f ? 0.f : lineSpacing;
+          penY += lineSpacing;
+        }
 
         // Increase the glyph index.
         index = nextIndex;
@@ -1551,6 +1572,7 @@ struct Engine::Impl
   Type mLayout;
   float mCursorWidth;
   float mDefaultLineSpacing;
+  float mDefaultLineSize;
 
   IntrusivePtr<Metrics> mMetrics;
 };
@@ -1632,6 +1654,16 @@ float Engine::GetDefaultLineSpacing() const
   return mImpl->mDefaultLineSpacing;
 }
 
+void Engine::SetDefaultLineSize( float lineSize )
+{
+  mImpl->mDefaultLineSize = lineSize;
+}
+
+float Engine::GetDefaultLineSize() const
+{
+  return mImpl->mDefaultLineSize;
+}
+
 } // namespace Layout
 
 } // namespace Text
index af693da..5641c47 100755 (executable)
@@ -152,6 +152,20 @@ public:
    */
   float GetDefaultLineSpacing() const;
 
+  /**
+   * @brief Sets the default line size.
+   *
+   * @param[in] lineSize The line size.
+   */
+  void SetDefaultLineSize( float lineSize );
+
+  /**
+   * @brief Retrieves the default line size.
+   *
+   * @return The line size.
+   */
+  float GetDefaultLineSize() const;
+
 private:
 
   // Undefined
index 5b424be..0256a43 100755 (executable)
@@ -337,6 +337,7 @@ PixelData Typesetter::Render( const Vector2& size, Toolkit::DevelText::TextDirec
     case VerticalAlignment::CENTER:
     {
       penY = static_cast<int>( 0.5f * ( size.height - layoutSize.height ) );
+      penY = penY < 0.f ? 0.f : penY;
       break;
     }
     case VerticalAlignment::BOTTOM:
old mode 100644 (file)
new mode 100755 (executable)
index 593e1e5..de41d0e
@@ -117,8 +117,8 @@ void ShapeText( const Vector<Character>& text,
 
   const Length currentNumberOfGlyphs = glyphs.Count();
   const Length numberOfGlyphsReserved = static_cast<Length>( numberOfCharacters * 1.3f );
-  glyphs.Resize( currentNumberOfGlyphs + numberOfGlyphsReserved, glyphInfo );
-  glyphToCharacterMap.Resize( currentNumberOfGlyphs + numberOfGlyphsReserved );
+  glyphs.Reserve( currentNumberOfGlyphs + numberOfGlyphsReserved );
+  glyphToCharacterMap.Reserve( currentNumberOfGlyphs + numberOfGlyphsReserved );
 
   // The actual number of glyphs.
   Length totalNumberOfGlyphs = currentNumberOfGlyphs;
index 6fd031f..694be22 100755 (executable)
@@ -64,7 +64,6 @@ const char * const PLACEHOLDER_FONT_STYLE = "fontStyle";
 const char * const PLACEHOLDER_POINT_SIZE = "pointSize";
 const char * const PLACEHOLDER_PIXEL_SIZE = "pixelSize";
 const char * const PLACEHOLDER_ELLIPSIS = "ellipsis";
-const unsigned int MAX_TEXT_LENGTH = 1024u * 32u;
 
 float ConvertToEven( float value )
 {
@@ -323,7 +322,7 @@ bool Controller::IsSmoothHandlePanEnabled() const
 
 void Controller::SetMaximumNumberOfCharacters( Length maxCharacters )
 {
-  mImpl->mMaximumNumberOfCharacters = std::min( maxCharacters, MAX_TEXT_LENGTH );
+  mImpl->mMaximumNumberOfCharacters = maxCharacters;
 }
 
 int Controller::GetMaximumNumberOfCharacters()
@@ -704,13 +703,6 @@ void Controller::SetText( const std::string& text )
       utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
     }
 
-    // Limit the text size. If the text size is too large, crash or deadlock will occur.
-    if( textSize > MAX_TEXT_LENGTH )
-    {
-      DALI_LOG_WARNING( "The text size is too large(%d), limit the length to 32,768u\n", textSize );
-      textSize = MAX_TEXT_LENGTH;
-    }
-
     //  Convert text into UTF-32
     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
     utf32Characters.Resize( textSize );
@@ -1472,6 +1464,22 @@ float Controller::GetDefaultLineSpacing() const
   return mImpl->mLayoutEngine.GetDefaultLineSpacing();
 }
 
+bool Controller::SetDefaultLineSize( float lineSize )
+{
+  if( std::fabs( lineSize - mImpl->mLayoutEngine.GetDefaultLineSize() ) > Math::MACHINE_EPSILON_1000 )
+  {
+    mImpl->mLayoutEngine.SetDefaultLineSize(lineSize);
+    mImpl->mRecalculateNaturalSize = true;
+    return true;
+  }
+  return false;
+}
+
+float Controller::GetDefaultLineSize() const
+{
+  return mImpl->mLayoutEngine.GetDefaultLineSize();
+}
+
 void Controller::SetInputColor( const Vector4& color )
 {
   if( NULL != mImpl->mEventData )
index 4e3f5a0..497bf07 100755 (executable)
@@ -1045,6 +1045,22 @@ public: // Default style & Input style
   float GetDefaultLineSpacing() const;
 
   /**
+   * @brief Sets the default line size.
+   *
+   * @param[in] lineSize The line size.
+   *
+   * @return True if lineSize has been updated, false otherwise
+   */
+  bool SetDefaultLineSize( float lineSize );
+
+  /**
+   * @brief Retrieves the default line size.
+   *
+   * @return The line size.
+   */
+  float GetDefaultLineSize() const;
+
+  /**
    * @brief Sets the input text's color.
    *
    * @param[in] color The input text's color.
index bd23926..43ab569 100755 (executable)
@@ -22,6 +22,9 @@
 #include <dali/public-api/animation/constraints.h>
 #include <dali/devel-api/rendering/renderer-devel.h>
 #include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/images/pixel-data-devel.h>
+#include <string.h>
 
 // INTERNAL HEADER
 #include <dali-toolkit/public-api/visuals/text-visual-properties.h>
@@ -453,21 +456,32 @@ void TextVisual::DoSetOnStage( Actor& actor )
   // Renderer needs textures and to be added to control
   mRendererUpdateNeeded = true;
 
+  mRendererList.push_back( mImpl->mRenderer );
+
   UpdateRenderer();
 }
 
-void TextVisual::DoSetOffStage( Actor& actor )
+void TextVisual::RemoveRenderer( Actor& actor )
 {
-  if( mImpl->mRenderer )
+  for( RendererContainer::iterator iter = mRendererList.begin(); iter != mRendererList.end(); ++iter)
   {
-    // Removes the renderer from the actor.
-    actor.RemoveRenderer( mImpl->mRenderer );
+    Renderer renderer = (*iter);
+    if( renderer )
+    {
+      // Removes the renderer from the actor.
+      actor.RemoveRenderer( renderer );
+    }
+  }
+  // Clear the renderer list
+  mRendererList.clear();
+}
 
-    RemoveTextureSet();
+void TextVisual::DoSetOffStage( Actor& actor )
+{
+  RemoveRenderer( actor );
 
-    // Resets the renderer.
-    mImpl->mRenderer.Reset();
-  }
+  // Resets the renderer.
+  mImpl->mRenderer.Reset();
 
   // Resets the control handle.
   mControl.Reset();
@@ -597,14 +611,8 @@ void TextVisual::UpdateRenderer()
 
   if( ( fabsf( relayoutSize.width ) < Math::MACHINE_EPSILON_1000 ) || ( fabsf( relayoutSize.height ) < Math::MACHINE_EPSILON_1000 ) || text.empty() )
   {
-    // Removes the texture set.
-    RemoveTextureSet();
-
-    // Remove any renderer previously set.
-    if( mImpl->mRenderer )
-    {
-      control.RemoveRenderer( mImpl->mRenderer );
-    }
+    // Remove the texture set and any renderer previously set.
+    RemoveRenderer( control );
 
     // Nothing else to do if the relayout size is zero.
     ResourceReady( Toolkit::Visual::ResourceStatus::READY );
@@ -618,14 +626,8 @@ void TextVisual::UpdateRenderer()
   {
     mRendererUpdateNeeded = false;
 
-    // Removes the texture set.
-    RemoveTextureSet();
-
-    // Remove any renderer previously set.
-    if( mImpl->mRenderer )
-    {
-      control.RemoveRenderer( mImpl->mRenderer );
-    }
+    // Remove the texture set and any renderer previously set.
+    RemoveRenderer( control );
 
     if( ( relayoutSize.width > Math::MACHINE_EPSILON_1000 ) &&
         ( relayoutSize.height > Math::MACHINE_EPSILON_1000 ) )
@@ -668,48 +670,196 @@ void TextVisual::UpdateRenderer()
 
       const bool styleEnabled = ( shadowEnabled || underlineEnabled || outlineEnabled || backgroundEnabled );
 
-      TextureSet textureSet = GetTextTexture( relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled );
-      mImpl->mRenderer.SetTextures( textureSet );
 
-      Shader shader = GetTextShader( mFactoryCache, hasMultipleTextColors, containsColorGlyph, styleEnabled );
-      mImpl->mRenderer.SetShader(shader);
+      AddRenderer( control, relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled );
 
-      mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
+      // Text rendered and ready to display
+      ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+    }
+  }
+}
 
-      mImpl->mRenderer.RegisterProperty( "uHasMultipleTextColors", static_cast<float>( hasMultipleTextColors ) );
+void TextVisual::AddTexture( TextureSet& textureSet, PixelData& data, Sampler& sampler, unsigned int textureSetIndex )
+{
+  Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
+                                  data.GetPixelFormat(),
+                                  data.GetWidth(),
+                                  data.GetHeight() );
+  texture.Upload( data );
+
+  textureSet.SetTexture( textureSetIndex, texture );
+  textureSet.SetSampler( textureSetIndex, sampler );
+}
 
-      mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON);
+PixelData TextVisual::ConvertToPixelData( unsigned char* buffer, int width, int height, int offsetPosition, const Pixel::Format textPixelFormat )
+{
+  int bpp = Pixel::GetBytesPerPixel( textPixelFormat );
+  unsigned int bufferSize = width * height * bpp;
+  unsigned char* dstBuffer = static_cast<unsigned char*>( malloc ( bufferSize ) );
+  memcpy( dstBuffer, buffer + offsetPosition * bpp, bufferSize );
+  PixelData pixelData = Dali::PixelData::New( dstBuffer,
+                                              bufferSize,
+                                              width,
+                                              height,
+                                              textPixelFormat,
+                                              Dali::PixelData::FREE );
+  return pixelData;
+}
 
-      //Register transform properties
-      mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+void TextVisual::CreateTextureSet( TilingInfo& info, Renderer& renderer, Sampler& sampler, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled )
+{
 
-      control.AddRenderer( mImpl->mRenderer );
+  TextureSet textureSet = TextureSet::New();
+  unsigned int textureSetIndex = 0u;
 
-      // Text rendered and ready to display
-      ResourceReady( Toolkit::Visual::ResourceStatus::READY );
-    }
+  // Convert the buffer to pixel data to make it a texture.
+  if( info.textBuffer )
+  {
+    PixelData data = ConvertToPixelData( info.textBuffer, info.width, info.height, info.offsetPosition, info.textPixelFormat );
+    AddTexture( textureSet, data, sampler, textureSetIndex );
+    ++textureSetIndex;
   }
+
+  if( styleEnabled && info.styleBuffer )
+  {
+    PixelData styleData = ConvertToPixelData( info.styleBuffer, info.width, info.height, info.offsetPosition, Pixel::RGBA8888 );
+    AddTexture( textureSet, styleData, sampler, textureSetIndex );
+    ++textureSetIndex;
+  }
+
+  if( containsColorGlyph && !hasMultipleTextColors && info.maskBuffer )
+  {
+    PixelData maskData = ConvertToPixelData( info.maskBuffer, info.width, info.height, info.offsetPosition, Pixel::L8 );
+    AddTexture( textureSet, maskData, sampler, textureSetIndex );
+  }
+
+  renderer.SetTextures( textureSet );
+
+  //Register transform properties
+  mImpl->mTransform.RegisterUniforms( renderer, Direction::LEFT_TO_RIGHT );
+
+  // Enable the pre-multiplied alpha to improve the text quality
+  renderer.SetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true );
+  renderer.RegisterProperty( PREMULTIPLIED_ALPHA, 1.0f );
+
+  // Set size and offset for the tiling.
+  renderer.RegisterProperty( SIZE, Vector2( info.width, info.height ) );
+  renderer.RegisterProperty( OFFSET, Vector2( info.offSet.x, info.offSet.y ) );
+  renderer.RegisterProperty( "uHasMultipleTextColors", static_cast<float>( hasMultipleTextColors ) );
+  renderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON);
+
+  mRendererList.push_back( renderer );
 }
 
-void TextVisual::RemoveTextureSet()
+
+void TextVisual::AddRenderer( Actor& actor, const Vector2& size, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled )
 {
-  if( mImpl->mFlags & Impl::IS_ATLASING_APPLIED )
+  Shader shader = GetTextShader( mFactoryCache, hasMultipleTextColors, containsColorGlyph, styleEnabled );
+  mImpl->mRenderer.SetShader( shader );
+
+  // Get the maximum size.
+  const int maxTextureSize = Dali::GetMaxTextureSize();
+
+  // No tiling required. Use the default renderer.
+  if( size.height < maxTextureSize )
+  {
+    TextureSet textureSet = GetTextTexture( size, hasMultipleTextColors, containsColorGlyph, styleEnabled );
+
+    mImpl->mRenderer.SetTextures( textureSet );
+    //Register transform properties
+    mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+    mImpl->mRenderer.RegisterProperty( "uHasMultipleTextColors", static_cast<float>( hasMultipleTextColors ) );
+    mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON);
+
+    mRendererList.push_back( mImpl->mRenderer );
+  }
+  // If the pixel data exceeds the maximum size, tiling is required.
+  else
   {
-    // Removes the text's image from the texture atlas.
-    Vector4 atlasRect;
+    // Filter mode needs to be set to linear to produce better quality while scaling.
+    Sampler sampler = Sampler::New();
+    sampler.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR );
+
+    // Create RGBA texture if the text contains emojis or multiple text colors, otherwise L8 texture
+    Pixel::Format textPixelFormat = ( containsColorGlyph || 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, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat );
+
+    int verifiedWidth = data.GetWidth();
+    int verifiedHeight = data.GetHeight();
+
+    // Set information for creating textures.
+    TilingInfo info( verifiedWidth, maxTextureSize, textPixelFormat );
+
+    // Get the buffer of text.
+    Dali::DevelPixelData::PixelDataBuffer textPixelData = Dali::DevelPixelData::ReleasePixelDataBuffer( data );
+    info.textBuffer = textPixelData.buffer;
+
+    if( styleEnabled )
+    {
+      // Create RGBA texture for all the text styles (without the text itself)
+      PixelData styleData = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888 );
+      Dali::DevelPixelData::PixelDataBuffer stylePixelData = Dali::DevelPixelData::ReleasePixelDataBuffer( styleData );
+      info.styleBuffer = stylePixelData.buffer;
+    }
+
+    if ( containsColorGlyph && !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, textDirection, Text::Typesetter::RENDER_MASK, false, Pixel::L8 );
+      Dali::DevelPixelData::PixelDataBuffer maskPixelData = Dali::DevelPixelData::ReleasePixelDataBuffer( maskData );
+      info.maskBuffer = maskPixelData.buffer;
+    }
+
+    // Get the current offset for recalculate the offset when tiling.
+    Property::Map retMap;
+    mImpl->mTransform.GetPropertyMap( retMap );
+    Vector2 offSet = retMap.Find( Dali::Toolkit::Visual::Transform::Property::OFFSET )->Get< Vector2 >();
+    info.offSet = offSet;
+
+    // Create a textureset in the default renderer.
+    CreateTextureSet( info, mImpl->mRenderer, sampler, hasMultipleTextColors, containsColorGlyph, styleEnabled );
 
-    const Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME );
-    if( index != Property::INVALID_INDEX )
+    verifiedHeight -= maxTextureSize;
+
+    Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
+
+    int offsetPosition = verifiedWidth * maxTextureSize;
+    // Create a renderer by cutting maxTextureSize.
+    while( verifiedHeight > 0 )
     {
-      const Property::Value& atlasRectValue = mImpl->mRenderer.GetProperty( index );
-      atlasRectValue.Get( atlasRect );
+      Renderer tilingRenderer = Renderer::New( geometry, shader );
+      tilingRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, Toolkit::DepthIndex::CONTENT );
+      // New offset position of buffer for tiling.
+      info.offsetPosition += offsetPosition;
+      // New height for tiling.
+      info.height = ( verifiedHeight - maxTextureSize ) > 0 ? maxTextureSize : verifiedHeight;
+      // New offset for tiling.
+      info.offSet.y += maxTextureSize;
+      // Create a textureset int the new tiling renderer.
+      CreateTextureSet( info, tilingRenderer, sampler, hasMultipleTextColors, containsColorGlyph, styleEnabled );
+
+      verifiedHeight -= maxTextureSize;
+    }
+  }
+
+  mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
 
-      const TextureSet& textureSet = mImpl->mRenderer.GetTextures();
-      mFactoryCache.GetAtlasManager()->Remove( textureSet, atlasRect );
+  for( RendererContainer::iterator iter = mRendererList.begin(); iter != mRendererList.end(); ++iter)
+  {
+    Renderer renderer = (*iter);
+    if( renderer )
+    {
+      actor.AddRenderer( renderer );
     }
   }
 }
 
+
 TextureSet TextVisual::GetTextTexture( const Vector2& size, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled )
 {
   // Filter mode needs to be set to linear to produce better quality while scaling.
@@ -729,31 +879,18 @@ TextureSet TextVisual::GetTextTexture( const Vector2& size, bool hasMultipleText
 
   // 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.
+  unsigned int textureSetIndex = 0u;
 
-  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 );
+  AddTexture( textureSet, data, sampler, textureSetIndex );
+  ++textureSetIndex;
 
   if ( styleEnabled )
   {
     // Create RGBA texture for all the text styles (without the text itself)
     PixelData styleData = mTypesetter->Render( size, textDirection, 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 );
+    AddTexture( textureSet, styleData, sampler, textureSetIndex );
+    ++textureSetIndex;
   }
 
   if ( containsColorGlyph && !hasMultipleTextColors )
@@ -761,23 +898,7 @@ TextureSet TextVisual::GetTextTexture( const Vector2& size, bool hasMultipleText
     // 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, textDirection, 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 );
-    }
+    AddTexture( textureSet, maskData, sampler, textureSetIndex );
   }
 
   return textureSet;
old mode 100644 (file)
new mode 100755 (executable)
index 6f47e45..16da39a
@@ -182,6 +182,48 @@ protected:
   void OnSetTransform() override;
 
 private:
+
+  struct TilingInfo
+  {
+    unsigned char* textBuffer;
+    unsigned char* styleBuffer;
+    unsigned char* maskBuffer;
+    int width;
+    int height;
+    Pixel::Format textPixelFormat;
+    int offsetPosition;
+    Vector2 offSet;
+
+    TilingInfo( int width, int height, Pixel::Format textPixelFormat )
+    : textBuffer( NULL ),
+      styleBuffer( NULL ),
+      maskBuffer( NULL ),
+      width( width ),
+      height( height ),
+      textPixelFormat( textPixelFormat ),
+      offsetPosition( 0 ),
+      offSet( 0.f, 0.f )
+    {
+    }
+
+    ~TilingInfo()
+    {
+      if( textBuffer )
+      {
+        free( textBuffer );
+      }
+      if( styleBuffer )
+      {
+        free( styleBuffer );
+      }
+      if( maskBuffer )
+      {
+        free( maskBuffer );
+      }
+    }
+
+  };
+
   /**
    * @brief Set the individual property to the given value.
    *
@@ -197,9 +239,50 @@ private:
   void UpdateRenderer();
 
   /**
-   * @brief Removes the texture set from the renderer.
+   * @brief Removes the text's renderer.
+   */
+  void RemoveRenderer( Actor& actor );
+
+  /**
+   * @brief Create a texture in textureSet and add it.
+   * @param[in] textureSet The textureSet to which the texture will be added.
+   * @param[in] data The PixelData to be uploaded to texture
+   * @param[in] sampler The sampler.
+   * @param[in] textureSetIndex The Index of TextureSet.
+   */
+  void AddTexture( TextureSet& textureSet, PixelData& data, Sampler& sampler, unsigned int textureSetIndex );
+
+  /**
+   * @brief Convert the buffer to pixelData.
+   * @param[in] buffer The Buffer to be converted to pixelData.
+   * @param[in] width The width of pixel data.
+   * @param[in] height The height of pixel data.
+   * @param[in] offsetPosition The The buffer's start position.
+   * @param[in] textPixelFormat The PixelForma of text.
+   */
+  PixelData ConvertToPixelData( unsigned char* buffer, int width, int height, int offsetPosition, const Pixel::Format textPixelFormat );
+
+  /**
+   * @brief Create the text's texture.
+   * @param[in] info This is the information you need to create a Tiling.
+   * @param[in] renderer The renderer to which the TextureSet will be added.
+   * @param[in] sampler The sampler.
+   * @param[in] hasMultipleTextColors Whether the text contains multiple colors.
+   * @param[in] containsColorGlyph Whether the text contains color glyph.
+   * @param[in] styleEnabled Whether the text contains any styles (e.g. shadow, underline, etc.).
    */
-  void RemoveTextureSet();
+  void CreateTextureSet( TilingInfo& info, Renderer& renderer, Sampler& sampler,  bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled );
+
+  /**
+   * Create renderer of the text for rendering.
+   * @param[in] actor The actor.
+   * @param[in] size The texture size.
+   * @param[in] hasMultipleTextColors Whether the text contains multiple colors.
+   * @param[in] containsColorGlyph Whether the text contains color glyph.
+   * @param[in] styleEnabled Whether the text contains any styles (e.g. shadow, underline, etc.).
+   */
+  void AddRenderer( Actor& actor, const Vector2& size, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled );
+
 
   /**
    * Get the texture of the text for rendering.
@@ -231,6 +314,8 @@ private:
 
 private:
 
+  typedef std::vector< Renderer > RendererContainer;
+
   /**
    * Used as an alternative to boolean so that it is obvious whether the text contains single or multiple text colors, and emoji and styles.
    */
@@ -247,12 +332,14 @@ private:
     };
   };
 
+
 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.
   Property::Index     mAnimatableTextColorPropertyIndex;  ///< The index of animatable text color property registered by the control.
   bool                mRendererUpdateNeeded:1;            ///< The flag to indicate whether the renderer needs to be updated.
+  RendererContainer   mRendererList;
 };
 
 } // namespace Internal