Support Ellipsis Position Property 60/259560/33
authorShrouq Sabah <s.sabah@samsung.com>
Wed, 9 Jun 2021 21:39:31 +0000 (00:39 +0300)
committerShrouq Sabah <s.sabah@samsung.com>
Tue, 13 Jul 2021 12:13:42 +0000 (15:13 +0300)
Added new property Ellipsis to TextEditor
Added new property Ellipsis_Position to TextLabel, TextField and TextEditor

Example:
textLabel.SetProperty(DevelTextLabel::Property::ELLIPSIS_POSITION, DevelText::EllipsisPosition::START);

Handled Ellipsis location for below cases:
Positions: END, START and MIDDLE
TextController: TextLabel, TextField and TextEditor
SingleLine and Muilt-lines with differnat LineWrap modes
Text direction LTR and RTL

END algorithm already exits
START and MIDDLE algorithms added according to END one

Change-Id: If059878f7128141169e95cf237b690ce900c70b3

48 files changed:
automated-tests/src/dali-toolkit-internal/CMakeLists.txt
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.h
automated-tests/src/dali-toolkit-internal/utc-Dali-BidirectionalSupport.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-LogicalModel.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Cursor.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Ellipsis.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Hyphen-Wrapping.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Layout.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Shaping.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-ViewModel.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-TextLabel-internal.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-VisualModel.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h
dali-toolkit/devel-api/controls/text-controls/text-field-devel.h
dali-toolkit/devel-api/controls/text-controls/text-label-devel.h
dali-toolkit/devel-api/text/text-enumerations-devel.h
dali-toolkit/devel-api/text/text-utils-devel.cpp
dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/text/bidirectional-line-info-run.h
dali-toolkit/internal/text/bidirectional-support.cpp
dali-toolkit/internal/text/bidirectional-support.h
dali-toolkit/internal/text/layouts/layout-engine.cpp
dali-toolkit/internal/text/layouts/layout-engine.h
dali-toolkit/internal/text/line-run.h
dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp
dali-toolkit/internal/text/rendering/text-typesetter.cpp
dali-toolkit/internal/text/rendering/view-model.cpp
dali-toolkit/internal/text/rendering/view-model.h
dali-toolkit/internal/text/text-controller-relayouter.cpp
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-controller.h
dali-toolkit/internal/text/text-enumerations-impl.cpp
dali-toolkit/internal/text/text-enumerations-impl.h
dali-toolkit/internal/text/text-model-interface.h
dali-toolkit/internal/text/text-model.cpp
dali-toolkit/internal/text/text-model.h
dali-toolkit/internal/text/text-view-interface.h
dali-toolkit/internal/text/text-view.cpp
dali-toolkit/internal/text/text-view.h
dali-toolkit/internal/text/visual-model-impl.cpp
dali-toolkit/internal/text/visual-model-impl.h

index 0a65397..d50921c 100755 (executable)
@@ -37,6 +37,7 @@ SET(TC_SOURCES
  utc-Dali-VisualModel.cpp
  utc-Dali-VisualUrl.cpp
  utc-Dali-Text-Hyphen-Wrapping.cpp
+ utc-Dali-Text-Ellipsis.cpp
 )
 
 IF(ELDBUS_AVAILABLE)
index b2a6f5a..64a8473 100755 (executable)
@@ -102,7 +102,9 @@ void CreateTextModel( const std::string& text,
                       ModelPtr& textModel,
                       MetricsPtr& metrics,
                       bool markupProcessorEnabled,
-                      LineWrap::Mode wrapMode )
+                      LineWrap::Mode wrapMode,
+                      bool ellipsisEnabled,
+                      DevelText::EllipsisPosition::Type ellipsisPosition)
 {
   textModel = Model::New(); ///< Pointer to the text's model.
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
@@ -133,6 +135,12 @@ void CreateTextModel( const std::string& text,
     utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
   }
 
+  //Ellipsis
+  textModel-> mElideEnabled = ellipsisEnabled;
+  textModel-> mVisualModel->SetTextElideEnabled(ellipsisEnabled);
+  textModel-> mEllipsisPosition = ellipsisPosition;
+  textModel-> mVisualModel->SetEllipsisPosition(ellipsisPosition);
+
   // 1) Convert to utf32
   Vector<Character>& utf32Characters = logicalModel->mText;
   utf32Characters.Resize( textSize );
@@ -343,7 +351,8 @@ void CreateTextModel( const std::string& text,
   layoutEngine.LayoutText( layoutParameters,
                            layoutSize,
                            false,
-                           isAutoScroll );
+                           isAutoScroll,
+                           ellipsisPosition);
 
   if( options.align )
   {
index 6e30bbb..ccfbe98 100644 (file)
@@ -56,6 +56,9 @@ struct LayoutOptions
  * @param[out] textModel Pointer to a text model instance.
  * @param[out] metrics Pointer to a wrapper around FontClient used to get metrics.
  * @param[in] markupProcessorEnabled Enable markup processor to use markup text.
+ * @param[in] wrapMode Line wrap mode.
+ * @param[in] ellipsisEnabled Whether the ellipsis layout option is enabled.
+ * @param[in] ellipsisPosition Where is the location the text elide.
  */
 void CreateTextModel( const std::string& text,
                       const Size& textArea,
@@ -65,7 +68,9 @@ void CreateTextModel( const std::string& text,
                       ModelPtr& textModel,
                       MetricsPtr& metrics,
                       bool markupProcessorEnabled,
-                      LineWrap::Mode wrapMode );
+                      LineWrap::Mode wrapMode,
+                      bool ellipsisEnabled,
+                      DevelText::EllipsisPosition::Type ellipsisPosition);
 
 /**
  * @brief Configures the text @p controller similarly to the one configured by the text-label.
index de772f3..84ecd2d 100644 (file)
@@ -112,7 +112,9 @@ bool SetBidirectionalInfoTest( const SetBidirectionalInfoData& data )
                    textModel,
                    metrics,
                    false,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -198,7 +200,9 @@ bool GetMirroredTextTest( const GetMirroredTextData& data )
                    textModel,
                    metrics,
                    false,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -275,7 +279,9 @@ bool GetCharactersDirectionTest( const GetCharactersDirectionData& data )
                    textModel,
                    metrics,
                    data.markupProcessorEnabled,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
index 8515172..a95b707 100755 (executable)
@@ -119,7 +119,9 @@ bool CreateParagraphTest( const CreateParagraphData& data )
                    textModel,
                    metrics,
                    false,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -182,7 +184,9 @@ bool FindParagraphTest( const FindParagraphData& data )
                    textModel,
                    metrics,
                    false,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -234,7 +238,9 @@ bool FetchBidirectionalLineInfoTest( const FetchBidirectionalLineInfoData& data
                    textModel,
                    metrics,
                    false,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -281,7 +287,9 @@ bool GetLogicalCharacterIndexTest( const GetLogicalCharacterIndexData& data )
                    textModel,
                    metrics,
                    false,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -345,7 +353,9 @@ bool GetLogicalCursorIndexTest( const GetLogicalCursorIndexData& data )
                    textModel,
                    metrics,
                    false,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
index 78d7cf8..377f976 100755 (executable)
@@ -112,7 +112,9 @@ bool GetClosestLineTest( const GetClosestLineData& data )
                    textModel,
                    metrics,
                    false,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -159,7 +161,9 @@ bool GetClosestCursorIndexTest( const GetClosestCursorIndexData& data )
                    textModel,
                    metrics,
                    false,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -210,7 +214,9 @@ bool GetCursorPositionTest( const GetCursorPositionData& data )
                    textModel,
                    metrics,
                    false,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -264,7 +270,9 @@ bool FindSelectionIndicesTest( const FindSelectionIndicesData& data )
                    textModel,
                    metrics,
                    false,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Ellipsis.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Ellipsis.cpp
new file mode 100755 (executable)
index 0000000..e5b8a88
--- /dev/null
@@ -0,0 +1,1848 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-utils.h>
+#include <dali-toolkit/internal/text/font-description-run.h>
+#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/internal/text/text-view.h>
+
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+
+namespace
+{
+
+  const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+
+  struct ElideData
+  {
+    std::string                                                description;
+    std::string                                                text;
+    bool                                                       isMultiLines;
+    DevelText::LineWrap::Mode                                  lineWrapMode;
+    DevelText::EllipsisPosition::Type                          ellipsisPosition;
+    bool                                                       isMarkup;
+    Vector2                                                    size;
+    unsigned int                                               numberOfLines;
+    unsigned int                                               numberOfGlyphs;
+    float*                                                     positions;
+  };
+
+
+  bool ElideTestViewModel( const ElideData& data )
+  {
+    std::cout << "  testing : " << data.description << std::endl;
+
+    // Load some fonts.
+    TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+    fontClient.SetDpi( 93u, 93u );
+
+    char* pathNamePtr = get_current_dir_name();
+    const std::string pathName( pathNamePtr );
+    free( pathNamePtr );
+
+    fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf" );
+    fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansHebrewRegular.ttf" );
+    fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansArabicRegular.ttf" );
+
+    // Creates a text controller.
+    ControllerPtr controller = Controller::New();
+
+    // Tests the rendering controller has been created.
+    TypesetterPtr typesetter = Typesetter::New( controller->GetTextModel() );
+    DALI_TEST_CHECK(typesetter);
+
+    // Tests the view model has been created.
+    ViewModel* model = typesetter->GetViewModel();
+    DALI_TEST_CHECK(model);
+
+    // Configures the text controller similarly to the text-label.
+    ConfigureTextLabel( controller );
+
+    // Sets a text and relais-out.
+    controller->SetMarkupProcessorEnabled( data.isMarkup );
+
+    controller->SetMultiLineEnabled( data.isMultiLines );
+    controller->SetLineWrapMode( (Text::LineWrap::Mode)(data.lineWrapMode) );
+    controller->SetEllipsisPosition( data.ellipsisPosition );
+
+    controller->SetText( data.text );
+    controller->Relayout( data.size );
+
+    // Elide the glyphs.
+    model->ElideGlyphs();
+
+    if( data.numberOfLines != model->GetNumberOfLines() )
+    {
+      std::cout << "  different number of lines : " << model->GetNumberOfLines() << ", expected : " << data.numberOfLines << std::endl;
+      return false;
+    }
+
+    Length numberOfGlyphs = model->GetNumberOfGlyphs();
+
+    if( data.numberOfGlyphs != numberOfGlyphs )
+    {
+      std::cout << "  different number of glyphs : " << numberOfGlyphs << ", expected : " << data.numberOfGlyphs << std::endl;
+      return false;
+    }
+
+    const Vector2* const layoutBuffer              = model->GetLayout();
+    const Length         numberOfLines             = model->GetNumberOfLines();
+    const GlyphIndex     startIndexOfGlyphs        = model->GetStartIndexOfElidedGlyphs();
+    const GlyphIndex     endIndexOfGlyphs          = model->GetEndIndexOfElidedGlyphs();
+    const GlyphIndex     firstMiddleIndexOfGlyphs  = model->GetFirstMiddleIndexOfElidedGlyphs();
+
+
+    if( numberOfLines != 0u )
+    {
+      Length   elidedLineIndex    = 0u;
+      for(Length lineIndex=0u; lineIndex < numberOfLines; lineIndex++)
+      {
+          const LineRun& tempLine         = *( model->GetLines() + elidedLineIndex);
+          if(tempLine.ellipsis)
+          {
+            elidedLineIndex = lineIndex;
+            break;
+          }
+      }
+      const LineRun& elidedLine                   = *( model->GetLines() + elidedLineIndex);
+      Length         numberOfLineGlyphs           = 0u;
+      Length         numberOfLineGlyphsSecondHalf = 0u;
+
+      switch(data.ellipsisPosition)
+      {
+        case DevelText::EllipsisPosition::START:
+        {
+          numberOfLineGlyphs = elidedLine.glyphRun.numberOfGlyphs - ( startIndexOfGlyphs - elidedLine.glyphRun.glyphIndex);
+          break;
+        }
+        case DevelText::EllipsisPosition::MIDDLE:
+        {
+          numberOfLineGlyphs = firstMiddleIndexOfGlyphs - elidedLine.glyphRun.glyphIndex +1u ;
+          break;
+        }
+        case DevelText::EllipsisPosition::END:
+        default:
+        {
+          numberOfLineGlyphs = endIndexOfGlyphs - elidedLine.glyphRun.glyphIndex + 1u;
+          break;
+        }
+      }
+
+      unsigned int index = 0u;
+      for( ; index < numberOfLineGlyphs; ++index )
+      {
+        if( *( data.positions + index ) != floor(elidedLine.alignmentOffset + ( *( layoutBuffer + index ) ).x ) )
+        {
+          std::cout << "  different layout :";
+          for( unsigned int i = 0; i < numberOfLineGlyphs; ++i )
+          {
+            std::cout << " " << floor( elidedLine.alignmentOffset + ( *( layoutBuffer + i ) ).x );
+          }
+          std::cout << std::endl;
+          std::cout << "          expected :";
+          for( unsigned int i = 0; i < numberOfLineGlyphs; ++i )
+          {
+            std::cout << " " << *( data.positions + i );
+          }
+          std::cout << std::endl;
+          return false;
+        }
+      }
+
+
+      for( ; index < numberOfLineGlyphsSecondHalf; ++index )
+      {
+        if( *( data.positions + index ) != floor(elidedLine.alignmentOffset + ( *( layoutBuffer + index ) ).x ) )
+        {
+          std::cout << "  different layout :";
+          for( unsigned int i = 0; i < numberOfLineGlyphsSecondHalf; ++i )
+          {
+            std::cout << " " << floor( elidedLine.alignmentOffset + ( *( layoutBuffer + i ) ).x );
+          }
+          std::cout << std::endl;
+          std::cout << "          expected :";
+          for( unsigned int i = 0; i < numberOfLineGlyphsSecondHalf; ++i )
+          {
+            std::cout << " " << *( data.positions + i );
+          }
+          std::cout << std::endl;
+          return false;
+        }
+      }
+
+    }
+
+    return true;
+  }
+
+  bool ElideTestTextView( const ElideData& data )
+  {
+    std::cout << "  testing : " << data.description << std::endl;
+
+    // Load some fonts.
+    TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+    fontClient.SetDpi( 93u, 93u );
+
+    char* pathNamePtr = get_current_dir_name();
+    const std::string pathName( pathNamePtr );
+    free( pathNamePtr );
+
+    fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf" );
+    fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansHebrewRegular.ttf" );
+    fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansArabicRegular.ttf" );
+
+    // Creates a text controller.
+    ControllerPtr controller = Controller::New();
+
+    if(data.isMultiLines)
+    {
+       // Configures the text controller similarly to the text-editor.
+       ConfigureTextEditor( controller );
+       controller->SetVerticalScrollEnabled( false );
+    }
+    else
+    {
+      // Configures the text controller similarly to the text-field.
+      ConfigureTextField( controller );
+    }
+
+    controller->SetDefaultFontFamily("TizenSansRegular");
+    controller->SetDefaultFontSize(12.0f, Text::Controller::POINT_SIZE);
+
+    controller->SetMultiLineEnabled( data.isMultiLines );
+    controller->SetLineWrapMode( (Text::LineWrap::Mode)(data.lineWrapMode) );
+
+    // Sets a text and relais-out.
+    controller->SetMarkupProcessorEnabled( data.isMarkup );
+
+    controller->SetTextElideEnabled( true );
+    controller->SetEllipsisPosition( data.ellipsisPosition );
+
+    controller->SetText( data.text );
+    controller->Relayout( data.size );
+
+    // Get view to elide the glyphs.
+    Text::ViewInterface& view = controller->GetView();
+
+    Length numberOfGlyphs = view.GetNumberOfGlyphs();
+
+    if(numberOfGlyphs == 0u)
+    {
+      return data.numberOfGlyphs == 0u;
+    }
+
+    Vector<GlyphInfo> glyphs;
+    glyphs.Resize(numberOfGlyphs);
+
+    Vector<Vector2> positions;
+    positions.Resize(numberOfGlyphs);
+
+    float alignmentOffset = 0u;
+    numberOfGlyphs = view.GetGlyphs(glyphs.Begin(),
+                                    positions.Begin(),
+                                    alignmentOffset,
+                                    0u,
+                                    numberOfGlyphs);
+
+    glyphs.Resize(numberOfGlyphs);
+    positions.Resize(numberOfGlyphs);
+
+
+    if( data.numberOfGlyphs != numberOfGlyphs )
+    {
+      std::cout << "  different number of glyphs : " << numberOfGlyphs << ", expected : " << data.numberOfGlyphs << std::endl;
+      return false;
+    }
+
+    // Tests the text model has been created.
+    const ModelInterface* textModel  = controller->GetTextModel();
+    DALI_TEST_CHECK(textModel);
+
+    if( data.numberOfLines != textModel->GetNumberOfLines() )
+    {
+      std::cout << "  different number of lines : " << textModel->GetNumberOfLines() << ", expected : " << data.numberOfLines << std::endl;
+      return false;
+    }
+
+    const Length     numberOfLines             = textModel->GetNumberOfLines();
+    const GlyphIndex startIndexOfGlyphs        = textModel->GetStartIndexOfElidedGlyphs();
+    const GlyphIndex endIndexOfGlyphs          = textModel->GetEndIndexOfElidedGlyphs();
+    const GlyphIndex firstMiddleIndexOfGlyphs  = textModel->GetFirstMiddleIndexOfElidedGlyphs();
+    const GlyphIndex secondMiddleIndexOfGlyphs = textModel->GetSecondMiddleIndexOfElidedGlyphs();
+
+    if( numberOfLines != 0u )
+    {
+      Length   elidedLineIndex    = 0u;
+      for(Length lineIndex=0u; lineIndex < numberOfLines; lineIndex++)
+      {
+          const LineRun& tempLine         = *( textModel->GetLines() + lineIndex);
+          if(tempLine.ellipsis)
+          {
+            elidedLineIndex = lineIndex;
+            break;
+          }
+      }
+      const LineRun& elidedLine         = *( textModel->GetLines() + elidedLineIndex);
+
+      Length         numberOfLineGlyphs           = 0u;
+      Length         numberOfLineGlyphsSecondHalf = 0u;
+
+      switch(data.ellipsisPosition)
+      {
+        case DevelText::EllipsisPosition::START:
+        {
+          numberOfLineGlyphs = elidedLine.glyphRun.numberOfGlyphs - ( startIndexOfGlyphs - elidedLine.glyphRun.glyphIndex);
+          break;
+        }
+        case DevelText::EllipsisPosition::MIDDLE:
+        {
+          numberOfLineGlyphs = firstMiddleIndexOfGlyphs == elidedLine.glyphRun.glyphIndex ? 0u : (firstMiddleIndexOfGlyphs - elidedLine.glyphRun.glyphIndex +1u);
+
+          if(elidedLine.isSplitToTwoHalves)
+          {
+            numberOfLineGlyphsSecondHalf = (elidedLine.glyphRunSecondHalf.glyphIndex + elidedLine.glyphRunSecondHalf.numberOfGlyphs) - secondMiddleIndexOfGlyphs ;
+
+          }
+          break;
+        }
+        case DevelText::EllipsisPosition::END:
+        default:
+        {
+          numberOfLineGlyphs = endIndexOfGlyphs - elidedLine.glyphRun.glyphIndex + 1u;
+          break;
+        }
+      }
+
+
+      unsigned int index = 0u;
+      for(  ; index < numberOfLineGlyphs; ++index )
+      {
+
+        if( *( data.positions + index ) != floor( elidedLine.alignmentOffset + positions[index].x ))
+        {
+          std::cout << "  different layout :";
+          for( unsigned int i = 0; i < numberOfLineGlyphs; ++i )
+          {
+            std::cout << " " << floor( elidedLine.alignmentOffset + positions[i].x );
+          }
+          std::cout << std::endl;
+          std::cout << "          expected :";
+          for( unsigned int i = 0; i < numberOfLineGlyphs; ++i )
+          {
+            std::cout << " " << *( data.positions + i );
+          }
+          std::cout << std::endl;
+          return false;
+        }
+      }
+
+      for( ; index < numberOfLineGlyphsSecondHalf; ++index )
+      {
+        if( *( data.positions + index ) != floor( elidedLine.alignmentOffset + positions[index].x ))
+        {
+          std::cout << "  different layout :";
+          for( unsigned int i = 0; i < numberOfLineGlyphsSecondHalf; ++i )
+          {
+            std::cout << " " << floor( elidedLine.alignmentOffset + positions[i].x );
+          }
+          std::cout << std::endl;
+          std::cout << "          expected :";
+          for( unsigned int i = 0; i < numberOfLineGlyphsSecondHalf; ++i )
+          {
+            std::cout << " " << *( data.positions + i );
+          }
+          std::cout << std::endl;
+          return false;
+        }
+      }
+    }
+
+    return true;
+  }
+
+}
+
+int UtcDaliTextLabelElideTextLocation(void)
+{
+  tet_infoline(" UtcDaliTextLabelElideTextLocation ");
+
+  Size textSize00( 100.f, 100.f );
+
+  Size  textSize01( 120.0f, 50.0f );
+  float positions01[] = { 0.f, 11.f, 23.f, 32.f, 42.f, 52.f, 62.f, 73.f, 83.f, 95.f };
+
+  Size  textSize02( 120.0f, 50.0f );
+  float positions02[] = { 0.f, 11.f, 23.f, 32.f, 42.f, 52.f, 62.f, 73.f, 83.f, 93.f, 103.f, 112.f, 0.f, 10.f, 22.f, 31.f, 41.f, 51.f, 61.f, 72.f, 82.f, 94.f };
+
+  Size  textSize03( 120.0f, 60.0f );
+  float positions03[] = { 0.f, 12.f, 21.f, 26.f, 30.f, 39.f, 45.f, 57.f, 61.f, 0.f, 10.f, 19.f, 29.f, 39.f, 46.f, 50.f, 66.f, 76.f, 85.f, 0.f, 15.f, 25.f, 30.f, 38.f, 48.f, 64.f, 73.f, 79.f, 93.f };
+
+  Size  textSize04( 120.0f, 60.0f );
+  float positions04[] = { 0.f, 12.f, 21.f, 26.f, 30.f, 39.f, 45.f, 57.f, 61.f, 67.f, 77.f, 86.f, 96.f, 106.f, 113.f, 0.f, 15.f, 25.f, 34.f, 39.f, 55.f, 65.f, 69.f, 78.f, 88.f, 104.f, 112.f, 0.f, 12.f, 21.f, 26.f, 30.f, 39.f, 45.f, 57.f, 61.f, 67.f, 77.f, 86.f, 98.f };
+
+  Size  textSize05( 110.0f, 60.0f );
+  float positions05[] = { 0.f, 12.f, 21.f, 26.f, 30.f, 39.f, 45.f, 57.f, 61.f, 67.f, 77.f, 0.f, 10.f, 20.f, 26.f, 31.f, 46.f, 56.f, 65.f, 70.f, 86.f, 96.f, 0.f, 8.f, 18.f, 34.f, 43.f, 49.f, 61.f, 71.f, 75.f, 81.f };
+
+  Size  textSize06( 110.0f, 60.0f );
+  float positions06[] = { 0.f, 12.f, 21.f, 26.f, 30.f, 39.f, 45.f, 57.f, 61.f, 0.f, 10.f, 19.f, 29.f, 39.f, 46.f, 50.f, 66.f, 76.f, 85.f, 0.f, 15.f, 25.f, 30.f, 38.f, 48.f, 64.f, 73.f, 81.f };
+
+  Size  textSize07( 120.0f, 50.0f );
+  float positions07[] = { 6.0f, 23.0f, 32.0f, 42.0f, 53.0f, 63.0f, 73.0f, 83.0f, 93.0f, 104.0f, 113.0f } ;
+
+  Size  textSize08( 120.0f, 50.0f );
+  float positions08[] = { 5.0f, 22.0f, 31.0f, 41.0f, 51.0f, 62.0f, 72.0f, 82.0f, 92.0f, 102.0f, 112.0f };
+
+  Size  textSize09( 120.0f, 60.0f );
+  float positions09[] = { 9.0f, 25.0f, 30.0f, 38.0f, 48.0f, 64.0f, 73.0f, 79.0f, 91.0f, 101.0f, 105.0f, 110.0f, 118.0f };
+
+  Size  textSize10( 120.0f, 60.0f );
+  float positions10[] = { 8.0f, 25.0f, 34.0f, 39.0f, 55.0f, 65.0f, 69.0f, 78.0f, 88.0f, 104.0f, 112.0f };
+
+  Size  textSize11( 100.0f, 60.0f );
+  float positions11[] = { 5.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f, 61.0f, 67.0f, 77.0f };
+
+  Size  textSize12( 100.0f, 60.0f );
+  float positions12[] = { 5.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f, 61.0f };
+
+  Size  textSize13( 120.0f, 60.0f );
+  float positions13[] = { 118.0f, 111.0f, 96.0f, 88.0f, 79.0f, 73.0f, 62.0f, 57.0f, 52.0f, 43.0f, 35.0f, 29.0f, 19.0f, 6.0f };
+
+  Size  textSize14( 120.0f, 60.0f );
+  float positions14[] = { 114.0f, 108.0f, 93.0f, 85.0f, 76.0f, 70.0f, 59.0f, 54.0f, 49.0f, 40.0f, 32.0f, 27.0f, 112.0f, 103.0f, 93.0f, 88.0f, 86.0f, 79.0f, 76.0f, 66.0f, 57.0f, 52.0f, 42.0f, 35.0f, 32.0f, 27.0f, 140.0f, 128.0f, 123.0f, 119.0f, 116.0f, 106.0f, 102.0f, 87.0f, 79.0f, 70.0f, 67.0f, 61.0f, 55.0f, 50.0f, 38.0f };
+
+  Size  textSize15( 110.0f, 60.0f );
+  float positions15[] = { 107.0f, 100.0f, 86.0f, 77.0f, 68.0f, 62.0f, 52.0f, 46.0f, 42.0f, 33.0f, 24.0f, 18.0f, 8.0f, 0.0f, 95.0f, 90.0f, 87.0f, 81.0f, 78.0f, 67.0f, 59.0f, 54.0f, 44.0f, 37.0f, 33.0f, 27.0f, 24.0f, 12.0f, 7.0f, 2.0f, 0.0f, 93.0f, 89.0f, 75.0f, 66.0f, 57.0f, 55.0f, 49.0f, 43.0f, 37.0f, 28.0f, 15.0f };
+
+  Size  textSize16( 110.0f, 60.0f );
+  float positions16[] = { 104.0f, 98.0f, 83.0f, 75.0f, 66.0f, 60.0f, 49.0f, 44.0f, 39.0f, 30.0f, 22.0f, 17.0f, 102.0f, 93.0f, 83.0f, 78.0f, 76.0f, 69.0f, 66.0f, 56.0f, 47.0f, 42.0f, 32.0f, 25.0f, 22.0f, 17.0f, 116.0f, 104.0f, 99.0f, 94.0f, 91.0f, 82.0f, 78.0f, 63.0f, 54.0f, 45.0f, 43.0f, 37.0f, 23.0f };
+
+  Size  textSize17( 110.0f, 60.0f );
+  float positions17[] = { 104.0f, 98.0f, 83.0f, 75.0f, 66.0f, 60.0f, 49.0f, 44.0f, 39.0f, 30.0f, 22.0f, 17.0f, 102.0f, 93.0f, 83.0f, 78.0f, 76.0f, 69.0f, 66.0f, 56.0f, 47.0f, 42.0f, 32.0f, 25.0f, 22.0f, 17.0f, 116.0f, 104.0f, 99.0f, 94.0f, 91.0f, 82.0f, 78.0f, 63.0f, 54.0f, 45.0f, 43.0f, 37.0f, 23.0f };
+
+  Size  textSize18( 120.0f, 60.0f );
+  float positions18[] = { 96.0f, 84.0f, 75.0f, 73.0f, 66.0f, 61.0f, 55.0f, 46.0f, 32.0f, 29.0f, 17.0f, 10.0f, 3.0f };
+
+  Size  textSize19( 120.0f, 60.0f );
+  float positions19[] = { 102.0f, 89.0f, 84.0f, 82.0f, 75.0f, 72.0f, 62.0f, 53.0f, 48.0f, 38.0f, 31.0f, 28.0f, 23.0f, };
+
+  Size  textSize20( 110.0f, 60.0f );
+  float positions20[] = { 89.0f, 81.0f, 78.0f, 67.0f, 59.0f, 54.0f, 44.0f, 37.0f, 33.0f, 27.0f, 24.0f, 12.0f, 7.0f, 2.0f, 0.0f };
+
+  Size  textSize21( 110.0f, 60.0f );
+  float positions21[] = { 92.0f, 79.0f, 74.0f, 72.0f, 65.0f, 62.0f, 52.0f, 43.0f, 38.0f, 28.0f, 21.0f, 18.0f, 13.0f };
+
+  Size  textSize22( 110.0f, 60.0f );
+  float positions22[] = {  92.0f, 79.0f, 74.0f, 72.0f, 65.0f, 62.0f, 52.0f, 43.0f, 38.0f, 28.0f, 21.0f, 18.0f, 13.0f };
+
+  Size  textSize23( 120.0f, 50.0f );
+  float positions23[] = { 0.0f, 11.0f, 22.0f, 33.0f, 46.0f };
+
+  Size  textSize24( 120.0f, 50.0f );
+  float positions24[] = { 0.0f, 11.0f, 23.0f, 32.0f, 42.0f, 52.0f, 62.0f, 73.0f, 83.0f, 95.0f };
+
+  Size  textSize25( 120.0f, 60.0f );
+  float positions25[] = { 0.0f, 12.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f, 61.0f, 0.0f, 10.0f, 19.0f, 29.0f, 39.0f, 46.0f, 50.0f, 68.0f };
+
+  Size  textSize26( 120.0f, 60.0f );
+  float positions26[] = { 0.0f, 12.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f, 61.0f, 67.0f, 77.0f, 86.0f, 96.0f, 106.0f, 113.0f, 0.0f, 15.0f, 25.0f, 34.0f, 39.0f, 55.0f, 65.0f, 69.0f, 78.0f, 90.0f };
+
+  Size  textSize27( 110.0f, 60.0f );
+  float positions27[] = { 0.0f, 12.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f, 61.0f, 67.0f, 77.0f, 0.0f, 10.0f, 20.0f, 26.0f, 31.0f, 46.0f, 56.0f, 65.0f, 72.0f };
+
+  Size  textSize28( 110.0f, 60.0f );
+  float positions28[] = { 0.0f, 12.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f, 61.0f, 0.0f, 10.0f, 19.0f, 29.0f, 39.0f, 46.0f, 50.0f, 68.0f };
+
+  Size  textSize29( 120.0f, 60.0f );
+  float positions29[] = { 116.0f, 109.0f, 94.0f, 86.0f, 77.0f, 71.0f, 60.0f };
+
+  Size  textSize30( 120.0f, 60.0f );
+  float positions30[] = { 114.0f, 108.0f, 93.0f, 85.0f, 76.0f, 70.0f, 59.0f, 54.0f, 49.0f, 40.0f, 32.0f, 27.0f, 112.0f, 103.0f, 93.0f, 88.0f, 86.0f, 79.0f, 76.0f, 66.0f, 57.0f, 52.0f, 33.0f };
+
+  Size  textSize31( 110.0f, 60.0f );
+  float positions31[] = { 107.0f, 100.0f, 86.0f, 77.0f, 68.0f, 62.0f, 52.0f, 46.0f, 42.0f, 33.0f, 24.0f, 18.0f, 8.0f, 0.0f, 95.0f, 90.0f, 87.0f, 81.0f, 78.0f, 67.0f, 59.0f, 54.0f, 44.0f, 37.0f, 33.0f, 27.0f, 24.0f, 9.0f};
+
+  Size  textSize32( 110.0f, 60.0f );
+  float positions32[] = {  104.0f, 98.0f, 83.0f, 75.0f, 66.0f, 60.0f, 49.0f, 44.0f, 39.0f, 30.0f, 22.0f, 17.0f, 102.0f, 93.0f, 83.0f, 78.0f, 76.0f, 69.0f, 66.0f, 56.0f, 47.0f, 42.0f, 23.0f };
+
+  Size  textSize33( 110.0f, 60.0f );
+  float positions33[] = { 104.0f, 98.0f, 83.0f, 75.0f, 66.0f, 60.0f, 49.0f, 44.0f, 39.0f, 30.0f, 22.0f, 17.0f, 102.0f, 93.0f, 83.0f, 78.0f, 76.0f, 69.0f, 66.0f, 56.0f, 47.0f, 42.0f, 23.0f };
+
+  Size  textSize34( 120.0f, 30.0f );
+  float positions34[] = { 0.0f, 12.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f, 61.0f, 67.0f, 77.0f, 86.0f, 98.0f };
+
+  Size  textSize35( 120.0f, 30.0f );
+  float positions35[] = { 2.0f, 20.0f, 29.0f, 39.0f, 44.0f, 60.0f, 69.0f, 74.0f, 83.0f, 92.0f, 108.0f };
+
+  Size  textSize36( 120.0f, 30.0f );
+  float positions36[] = { 0.0f, 12.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f };
+
+  struct ElideData data[] =
+  {
+    {
+      "void text",
+      "",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize00,
+      0u,
+      0u,
+      nullptr
+    },
+
+    {
+      "void text",
+      "",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize00,
+      0u,
+      0u,
+      nullptr
+    },
+
+    {
+      "void text",
+      "",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize00,
+      0u,
+      0u,
+      nullptr
+    },
+
+   //END LTR cases
+    {
+      "EllipsisPosition: TextLabel: Basic case SingleLine LTR END",
+      "A0123456789 B0123456789 C0123456789 D0123456789 ",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize01,
+      1u,
+      10u,
+      positions01
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Basic case Mulitlines LineWrap-WORD LTR END",
+      "A0123456789 B0123456789 C0123456789 D0123456789 ",
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize02,
+      2u,
+      22u,
+      positions02
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-WORD LTR END",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize03,
+      3u,
+      29u,
+      positions03
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-CHARACTER LTR END",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::CHARACTER,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize04,
+      3u,
+      40u,
+      positions04
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-HYPHAN LTR END",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::HYPHENATION,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize05,
+      3u,
+      32u,
+      positions05
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-MIXED LTR END",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::MIXED,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize06,
+      3u,
+      28u,
+      positions06
+    },
+
+   //START LTR cases
+    {
+      "EllipsisPosition: TextLabel: Basic case SingleLine LTR START",
+      "A0123456789 B0123456789 C0123456789 D0123456789 ",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize07,
+      1u,
+      11u,
+      positions07
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Basic case Mulitlines LineWrap-WORD LTR START",
+      "A0123456789 B0123456789 C0123456789 D0123456789 ",
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize08,
+      2u,
+      23u,
+      positions08
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-WORD LTR START",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize09,
+      3u,
+      33u,
+      positions09
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-CHARACTER LTR START",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::CHARACTER,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize10,
+      3u,
+      37u,
+      positions10
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-HYPHAN LTR START",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::HYPHENATION,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize11,
+      3u,
+      25u,
+      positions11
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-MIXED LTR START",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::MIXED,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize12,
+      3u,
+      25u,
+      positions12
+    },
+
+  //END RTL cases
+    {
+      "EllipsisPosition: TextLabel: SingleLine RTL END",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize13,
+      1u,
+      14u,
+      positions13
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-WORD RTL END",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize14,
+      3u,
+      41u,
+      positions14
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-CHARACTER RTL END",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::CHARACTER,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize15,
+      3u,
+      42u,
+      positions15
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-HYPHENATION RTL END",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::HYPHENATION,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize16,
+      3u,
+      39u,
+      positions16
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-MIXED RTL END",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::MIXED,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize17,
+      3u,
+      39u,
+      positions17
+    },
+
+   //START RTL cases
+    {
+      "EllipsisPosition: TextLabel: SingleLine RTL START",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize18,
+      1u,
+      13u,
+      positions18
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-WORD RTL START",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize19,
+      3u,
+      33u,
+      positions19
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-CHARACTER RTL START",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::CHARACTER,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize20,
+      3u,
+      30u,
+      positions20
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-HYPHENATION RTL START",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::HYPHENATION,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize21,
+      3u,
+      33u,
+      positions21
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-MIXED RTL START",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::MIXED,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize22,
+      3u,
+      33u,
+      positions22
+    },
+
+  //MIDDLE LTR cases
+    {
+      "EllipsisPosition: TextLabel: Basic case SingleLine LTR MIDDLE",
+      "ABCDEFGHIJKLMNPQRSTUVWXYZ abcdefghijklmnpqrstuvwxyz",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize23,
+      1u,
+      10u,
+      positions23
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Basic case Mulitlines LineWrap-WORD LTR MIDDLE",
+      "A0123456789 B0123456789 C0123456789 D0123456789 ",
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize24,
+      2u,
+      22u,
+      positions24
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-WORD LTR MIDDLE",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Goodbye" ,
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize25,
+      3u,
+      24u,
+      positions25
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-CHARACTER LTR MIDDLE",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Goodbye" ,
+      true,
+      DevelText::LineWrap::CHARACTER,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize26,
+      3u,
+      36u,
+      positions26
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-HYPHAN LTR MIDDLE",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Goodbye" ,
+      true,
+      DevelText::LineWrap::HYPHENATION,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize27,
+      3u,
+      27u,
+      positions27
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-MIXED LTR MIDDLE",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Goodbye" ,
+      true,
+      DevelText::LineWrap::MIXED,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize28,
+      3u,
+      24u,
+      positions28
+    },
+
+//MIDDLE RTL cases
+    {
+      "EllipsisPosition: TextLabel: SingleLine RTL MIDDLE",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize29,
+      1u,
+      12u,
+      positions29
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-WORD RTL MIDDLE",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize30,
+      3u,
+      31u,
+      positions30
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-CHARACTER RTL MIDDLE",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::CHARACTER,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize31,
+      3u,
+      30u,
+      positions31
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-HYPHENATION RTL MIDDLE",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::HYPHENATION,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize32,
+      3u,
+      31u,
+      positions32
+    },
+
+    {
+      "EllipsisPosition: TextLabel: Mulitlines LineWrap-MIXED RTL MIDDLE",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::MIXED,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize33,
+      3u,
+      31u,
+      positions33
+    },
+
+    {
+      "EllipsisPosition: TextLabel: One-Line for Mulitlines LineWrap-WORD LTR END",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize34,
+      1u,
+      13u,
+      positions34
+    },
+
+    {
+      "EllipsisPosition: TextLabel: One-Line for Mulitlines LineWrap-WORD LTR START",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize35,
+      1u,
+      11u,
+      positions35
+    },
+
+    {
+      "EllipsisPosition: TextLabel: One-Line for Mulitlines LineWrap-WORD LTR MIDDLE",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize36,
+      1u,
+      12u,
+      positions36
+    },
+
+  };
+  const unsigned int numberOfTests = 39u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !ElideTestViewModel( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+
+int UtcDaliTextFieldlElideTextLocation(void)
+{
+  tet_infoline(" UtcDaliTextFieldlElideTextLocation ");
+
+  Size textSize00( 100.f, 100.f );
+
+  Size  textSize01( 120.0f, 50.0f );
+  float positions01[] = { 0.0f, 11.0f, 23.0f, 32.0f, 42.0f, 52.0f, 62.0f, 73.0f, 83.0f, 95.0f };
+
+  Size  textSize02( 120.0f, 50.0f );
+  float positions02[] = { 0.0f, 12.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f, 61.0f, 67.0f, 77.0f, 86.0f, 98.0f };
+
+  Size  textSize03( 120.0f, 50.0f );
+  float positions03[] = { 118.0f, 111.0f, 97.0f, 89.0f, 80.0f, 74.0f, 63.0f, 58.0f, 53.0f, 44.0f, 35.0f, 29.0f, 20.0f, 7.0f };
+
+  Size  textSize04( 120.0f, 50.0f );
+  float positions04[] = { 6.0f, 23.0f, 32.0f, 42.0f, 53.0f, 63.0f, 73.0f, 83.0f, 93.0f, 104.0f, 113.0f };
+
+  Size  textSize05( 120.0f, 50.0f );
+  float positions05[] = { 2.0f, 20.0f, 29.0f, 39.0f, 44.0f, 60.0f, 69.0f, 74.0f, 83.0f, 92.0f, 108.0f };
+
+  Size  textSize06( 120.0f, 50.0f );
+  float positions06[] = { 99.0f, 87.0f, 78.0f, 76.0f, 69.0f, 64.0f, 58.0f, 49.0f, 35.0f, 32.0f, 20.0f, 13.0f, 6.0f };
+
+  Size  textSize07( 120.0f, 50.0f );
+  float positions07[] = { 0.0f, 11.0f, 23.0f, 32.0f, 42.0f, 57.0f, 73.0f };
+
+  Size  textSize08( 120.0f, 50.0f );
+  float positions08[] = { 0.0f, 12.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f, 61.0f, 67.0f, 77.0f, 86.0f, 98.0f };
+
+  Size  textSize09( 120.0f, 50.0f );
+  float positions09[] = { 118.0f, 111.0f, 97.0f, 89.0f, 80.0f, 74.0f, 63.0f, 58.0f, 53.0f, 44.0f, 35.0f, 29.0f, 20.0f, 7.0f };
+
+  Size  textSize10( 120.0f, 50.0f );
+  float positions10[] = { 118.0f, 113.0f, 107.0f, 102.0f, 97.0f, 92.0f, 87.0f, 82.0f, 79.0f, 72.0f, 57.0f, 49.0f, 40.0f, 34.0f, 23.0f, 11.0f };
+
+  Size  textSize11( 120.0f, 50.0f );
+  float positions11[] = { 95.0f, 78.0f, 75.0f, 64.0f, 56.0f, 49.0f, 44.0f, 39.0f, 34.0f, 29.0f, 23.0f, 18.0f, 13.0f, 8.0f, 3.0f };
+
+  Size  textSize12( 120.0f, 50.0f );
+  float positions12[] = { 113.0f, 108.0f, 103.0f, 98.0f, 93.0f, 88.0f, 83.0f, 78.0f, 74.0f, 67.0f };
+
+  struct ElideData data[] =
+  {
+    {
+      "void text",
+      "",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize00,
+      0u,
+      0u,
+      nullptr
+    },
+
+    {
+      "void text",
+      "",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize00,
+      0u,
+      0u,
+      nullptr
+    },
+
+    {
+      "void text",
+      "",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize00,
+      0u,
+      0u,
+      nullptr
+    },
+
+    {
+      "EllipsisPosition: TextField: Basic case SingleLine LTR END",
+      "A0123456789 B0123456789 C0123456789 D0123456789 ",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize01,
+      1u,
+      10u,
+      positions01
+    },
+
+    {
+      "EllipsisPosition: TextField: SingleLine LTR END",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize02,
+      1u,
+      13u,
+      positions02
+    },
+
+    {
+      "EllipsisPosition: TextField: SingleLine RTL END",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize03,
+      1u,
+      14u,
+      positions03
+    },
+
+    {
+      "EllipsisPosition: TextField: Basic case SingleLine LTR START",
+      "A0123456789 B0123456789 C0123456789 D0123456789 ",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize04,
+      1u,
+      11u,
+      positions04
+    },
+
+    {
+      "EllipsisPosition: TextField: SingleLine LTR START",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize05,
+      1u,
+      11u,
+      positions05
+    },
+
+    {
+      "EllipsisPosition: TextField: SingleLine RTL START",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize06,
+      1u,
+      13u,
+      positions06
+    },
+
+    {
+      "EllipsisPosition: TextField: Basic case SingleLine LTR MIDDLE",
+      "A0123456789 B0123456789 C0123456789 D0123456789 ",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize07,
+      1u,
+      11u,
+      positions07
+    },
+
+    {
+      "EllipsisPosition: TextField: SingleLine LTR MIDDLE",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Goodbye" ,
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize08,
+      1u,
+      13u,
+      positions08
+    },
+
+    {
+      "EllipsisPosition: TextField: SingleLine RTL MIDDLE",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize09,
+      1u,
+      12u,
+      positions09
+    },
+
+    {
+      "EllipsisPosition: TextField: Head and Tail whitespaces RTL END",
+      "        السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة         ",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize10,
+      1u,
+      16u,
+      positions10
+    },
+
+    {
+      "EllipsisPosition: TextField: Head and Tail whitespaces RTL START",
+      "        السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة         ",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize11,
+      1u,
+      15u,
+      positions11
+    },
+
+    {
+      "EllipsisPosition: TextField: Head and Tail whitespaces RTL MIDDLE",
+      "        السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة         ",
+      false,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize12,
+      1u,
+      20u,
+      positions12
+    },
+
+  };
+
+  const unsigned int numberOfTests = 15u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !ElideTestTextView( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+  tet_result(TET_PASS);
+  END_TEST;
+
+}
+
+
+int UtcDaliTextEditorElideTextLocation(void)
+{
+  tet_infoline(" UtcDaliTextEditorElideTextLocation ");
+
+  Size textSize00( 100.f, 100.f );
+
+  Size  textSize01( 120.0f, 50.0f );
+  float positions01[] = { 0.0f, 11.0f, 23.0f, 32.0f, 42.0f, 52.0f, 62.0f, 73.0f, 83.0f, 93.0f, 103.0f, 112.0f, 0.0f, 10.0f, 22.0f, 31.0f, 41.0f, 51.0f, 61.0f, 72.0f, 82.0f, 94.0f };
+
+  Size  textSize02( 120.0f, 60.0f );
+  float positions02[] = { 0.0f, 12.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f, 61.0f, 0.0f, 10.0f, 19.0f, 29.0f, 39.0f, 46.0f, 50.0f, 66.0f, 76.0f, 85.0f, 0.0f, 15.0f, 25.0f, 30.0f, 38.0f, 48.0f, 64.0f, 73.0f, 79.0f, 93.0f };
+
+  Size  textSize03( 120.0f, 60.0f );
+  float positions03[] = { 0.0f, 12.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f, 61.0f, 67.0f, 77.0f, 86.0f, 96.0f, 106.0f, 113.0f, 0.0f, 15.0f, 25.0f, 34.0f, 39.0f, 55.0f, 65.0f, 69.0f, 78.0f, 88.0f, 104.0f, 112.0f, 0.0f, 12.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f, 61.0f, 67.0f, 77.0f, 86.0f, 98.0f };
+
+  Size  textSize04( 110.0f, 60.0f );
+  float positions04[] = { 0.0f, 12.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f, 61.0f, 67.0f, 77.0f, 0.0f, 10.0f, 20.0f, 26.0f, 31.0f, 46.0f, 56.0f, 65.0f, 70.0f, 86.0f, 96.0f, 0.0f, 8.0f, 18.0f, 34.0f, 43.0f, 49.0f, 61.0f, 71.0f, 75.0f, 81.0f };
+
+  Size  textSize05( 110.0f, 60.0f );
+  float positions05[] = { 0.0f, 12.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f, 61.0f, 0.0f, 10.0f, 19.0f, 29.0f, 39.0f, 46.0f, 50.0f, 66.0f, 76.0f, 85.0f, 0.0f, 15.0f, 25.0f, 30.0f, 38.0f, 48.0f, 64.0f, 73.0f, 81.0f };
+
+  Size  textSize06( 120.0f, 50.0f );
+  float positions06[] = { 5.0f, 22.0f, 31.0f, 41.0f, 51.0f, 62.0f, 72.0f, 82.0f, 92.0f, 102.0f, 112.0f };
+
+  Size  textSize07( 120.0f, 60.0f );
+  float positions07[] = { 9.f, 25.f, 30.f, 38.f, 48.f, 64.f, 73.f, 79.f, 91.f, 101.f, 105.f, 110.f, 118.f };
+
+  Size  textSize08( 120.0f, 60.0f );
+  float positions08[] = { 8.f, 25.f, 34.f, 39.f, 55.f, 65.f, 69.f, 78.f, 88.f, 104.f, 112.f };
+
+  Size  textSize09( 100.0f, 60.0f );
+  float positions09[] = { 5.f, 21.f, 26.f, 30.f, 39.f, 45.f, 57.f, 61.f, 67.f, 77.f  };
+
+  Size  textSize10( 100.0f, 60.0f );
+  float positions10[] = { 5.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f, 61.0f, 67.0f, 77.0f };
+
+  Size  textSize11( 120.0f, 60.0f );
+  float positions11[] = { 119.0f, 112.0f, 98.0f, 89.0f, 80.0f, 74.0f, 63.0f, 58.0f, 53.0f, 45.0f, 36.0f, 31.0f, 112.0f, 103.0f, 93.0f };
+
+  Size  textSize12( 110.0f, 60.0f );
+  float positions12[] = { 115.0f, 108.0f, 94.0f, 85.0f, 76.0f, 70.0f, 60.0f, 54.0f, 50.0f, 41.0f, 32.0f };
+
+  Size  textSize13( 110.0f, 60.0f );
+  float positions13[] = { 113.0f, 106.0f, 92.0f, 83.0f, 74.0f, 68.0f, 58.0f, 52.0f, 48.0f, 39.0f, 30.0f, 25.0f, 106.0f };
+
+  Size  textSize14( 110.0f, 60.0f );
+  float positions14[] = { 113.0f, 106.0f, 92.0f, 83.0f, 74.0f, 68.0f, 58.0f, 52.0f, 48.0f, 39.0f, 30.0f, 25.0f, 106.0f };
+
+  Size  textSize15( 120.0f, 60.0f );
+  float positions15[] = { 125.f, 112.f, 107.f, 105.f, 98.f, 95.f, 85.f, 76.f, 71.f, 61.f, 54.f, 51.f, 46.f };
+
+  Size  textSize16( 110.0f, 60.0f );
+  float positions16[] = { 89.f, 81.f, 78.f, 67.f, 59.f, 54.f, 44.f, 37.f, 33.f, 27.f, 24.f, 12.f, 7.f, 2.f, 0.f };
+
+  Size  textSize17( 110.0f, 60.0f );
+  float positions17[] = { 105.f, 92.f, 87.f, 85.f, 78.f, 75.f, 65.f, 56.f, 51.f, 41.f, 34.f, 31.f, 26.f };
+
+  Size  textSize18( 110.0f, 60.0f );
+  float positions18[] = { 105.f, 92.f, 87.f, 85.f, 78.f, 75.f, 65.f, 56.f, 51.f, 41.f, 34.f, 31.f, 26.f };
+
+  Size  textSize19( 120.0f, 50.0f );
+  float positions19[] = { 0.f, 11.f, 23.f, 32.f, 42.f, 52.f, 62.f, 73.f, 83.f, 95.f };
+
+  Size  textSize20( 120.0f, 60.0f );
+  float positions20[] = { 0.f, 12.f, 21.f, 26.f, 30.f, 39.f, 45.f, 57.f, 61.f, 0.f, 10.f, 19.f, 29.f, 39.f, 46.f, 50.f, 68.f };
+
+  Size  textSize21( 120.0f, 60.0f );
+  float positions21[] = { 0.f, 12.f, 21.f, 26.f, 30.f, 39.f, 45.f, 57.f, 61.f, 67.f, 77.f, 86.f, 96.f, 106.f, 113.f, 0.f, 15.f, 25.f, 34.f, 39.f, 55.f, 65.f, 69.f, 78.f, 90.f };
+
+  Size  textSize22( 110.0f, 60.0f );
+  float positions22[] = { 0.f, 12.f, 21.f, 26.f, 30.f, 39.f, 45.f, 57.f, 61.f, 67.f, 77.f, 0.f, 10.f, 20.f, 26.f, 31.f, 46.f, 56.f, 65.f, 72.f };
+
+  Size  textSize23( 110.0f, 60.0f );
+  float positions23[] = { 0.f, 12.f, 21.f, 26.f, 30.f, 39.f, 45.f, 57.f, 61.f, 0.f, 10.f, 19.f, 29.f, 39.f, 46.f, 50.f, 68.f };
+
+  Size  textSize24( 120.0f, 60.0f );
+  float positions24[] = { 137.0f, 131.0f, 116.0f, 108.0f, 99.0f, 93.0f, 82.0f, 77.0f, 72.0f, 63.0f, 55.0f };
+
+  Size  textSize25( 110.0f, 60.0f );
+  float positions25[] = { 107.f, 100.f, 86.f, 77.f, 68.f, 62.f, 52.f, 46.f, 42.f, 33.f, 24.f, 18.f, 8.f, 0.f, 95.f, 90.f, 87.f, 81.f, 78.f, 67.f, 59.f, 54.f, 44.f, 37.f, 33.f, 27.f, 24.f, 9.f };
+
+  Size  textSize26( 110.0f, 60.0f );
+  float positions26[] = { 117.0f, 111.0f, 96.0f, 88.0f, 79.0f, 73.0f, 62.0f, 57.0f, 52.0f, 43.0f, 35.0f };
+
+  Size  textSize27( 110.0f, 60.0f );
+  float positions27[] = { 117.0f, 111.0f, 96.0f, 88.0f, 79.0f, 73.0f, 62.0f, 57.0f, 52.0f, 43.0f, 35.0f };
+
+  Size  textSize28( 120.0f, 30.0f );
+  float positions28[] = { 0.0f, 12.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f, 61.0f, 67.0f, 77.0f, 86.0f, 98.0f };
+
+  Size  textSize29( 120.0f, 30.0f );
+  float positions29[] = { 2.0f, 20.0f, 29.0f, 39.0f, 44.0f, 60.0f, 69.0f, 74.0f, 83.0f, 92.0f, 108.0f };
+
+  Size  textSize30( 120.0f, 30.0f );
+  float positions30[] = { 0.0f, 12.0f, 21.0f, 26.0f, 30.0f, 39.0f, 45.0f, 57.0f };
+
+
+  struct ElideData data[] =
+  {
+    {
+      "void text",
+      "",
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize00,
+      0u,
+      0u,
+      nullptr
+    },
+
+    {
+      "void text",
+      "",
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize00,
+      0u,
+      0u,
+      nullptr
+    },
+
+    {
+      "void text",
+      "",
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize00,
+      0u,
+      0u,
+      nullptr
+    },
+
+   //END LTR cases
+
+    {
+      "EllipsisPosition: TextEditor: Basic case Mulitlines LineWrap-WORD LTR END",
+      "A0123456789 B0123456789 C0123456789 D0123456789 ",
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize01,
+      2u,
+      22u,
+      positions01
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-WORD LTR END",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize02,
+      3u,
+      29u,
+      positions02
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-CHARACTER LTR END",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::CHARACTER,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize03,
+      3u,
+      40u,
+      positions03
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-HYPHAN LTR END",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::HYPHENATION,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize04,
+      3u,
+      32u,
+      positions04
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-MIXED LTR END",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::MIXED,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize05,
+      3u,
+      28u,
+      positions05
+    },
+
+   //START LTR cases
+
+    {
+      "EllipsisPosition: TextEditor: Basic case Mulitlines LineWrap-WORD LTR START",
+      "A0123456789 B0123456789 C0123456789 D0123456789 ",
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize06,
+      2u,
+      23u,
+      positions06
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-WORD LTR START",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize07,
+      3u,
+      33u,
+      positions07
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-CHARACTER LTR START",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::CHARACTER,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize08,
+      3u,
+      37u,
+      positions08
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-HYPHAN LTR START",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::HYPHENATION,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize09,
+      3u,
+      25u,
+      positions09
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-MIXED LTR START",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::MIXED,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize10,
+      3u,
+      25u,
+      positions10
+    },
+
+  //END RTL cases
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-WORD RTL END",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize11,
+      3u,
+      41u,
+      positions11
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-CHARACTER RTL END",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::CHARACTER,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize12,
+      3u,
+      42u,
+      positions12
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-HYPHENATION RTL END",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::HYPHENATION,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize13,
+      3u,
+      39u,
+      positions13
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-MIXED RTL END",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::MIXED,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize14,
+      3u,
+      39u,
+      positions14
+    },
+
+   //START RTL cases
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-WORD RTL START",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize15,
+      3u,
+      33u,
+      positions15
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-CHARACTER RTL START",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::CHARACTER,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize16,
+      3u,
+      30u,
+      positions16
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-HYPHENATION RTL START",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::HYPHENATION,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize17,
+      3u,
+      33u,
+      positions17
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-MIXED RTL START",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::MIXED,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize18,
+      3u,
+      33u,
+      positions18
+    },
+
+//MIDDLE LTR cases
+
+    {
+      "EllipsisPosition: TextEditor: Basic case Mulitlines LineWrap-WORD LTR MIDDLE",
+      "A0123456789 B0123456789 C0123456789 D0123456789 ",
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize19,
+      2u,
+      22u,
+      positions19
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-WORD LTR MIDDLE",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize20,
+      3u,
+      24u,
+      positions20
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-CHARACTER LTR MIDDLE",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::CHARACTER,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize21,
+      3u,
+      36u,
+      positions21
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-HYPHAN LTR MIDDLE",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::HYPHENATION,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize22,
+      3u,
+      27u,
+      positions22
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-MIXED LTR MIDDLE",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::MIXED,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize23,
+      3u,
+      24u,
+      positions23
+    },
+
+//MIDDLE RTL cases
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-WORD RTL MIDDLE",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize24,
+      3u,
+      31u,
+      positions24
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-CHARACTER RTL MIDDLE",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::CHARACTER,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize25,
+      3u,
+      30u,
+      positions25
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-HYPHENATION RTL MIDDLE",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::HYPHENATION,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize26,
+      3u,
+      31u,
+      positions26
+    },
+
+    {
+      "EllipsisPosition: TextEditor: Mulitlines LineWrap-MIXED RTL MIDDLE",
+      "السلام عليكم مرحبا اهلا هذا اختبار شكرا للمساعدة",
+      true,
+      DevelText::LineWrap::MIXED,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize27,
+      3u,
+      31u,
+      positions27
+    },
+
+    {
+      "EllipsisPosition: TextEditor: One-Line for Mulitlines LineWrap-WORD LTR END",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::END,
+      false,
+      textSize28,
+      1u,
+      13u,
+      positions28
+    },
+
+    {
+      "EllipsisPosition: TextEditor: One-Line for Mulitlines LineWrap-WORD LTR START",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::START,
+      false,
+      textSize29,
+      1u,
+      11u,
+      positions29
+    },
+
+    {
+      "EllipsisPosition: TextEditor: One-Line for Mulitlines LineWrap-WORD LTR MIDDLE",
+      "Hello Hi Experimen Welcome Hello Hi Experimen Welcome" ,
+      true,
+      DevelText::LineWrap::WORD,
+      DevelText::EllipsisPosition::MIDDLE,
+      false,
+      textSize30,
+      1u,
+      12u,
+      positions30
+    },
+
+  };
+  const unsigned int numberOfTests = 33u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !ElideTestTextView( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
index ccc8463..402cc40 100755 (executable)
@@ -91,7 +91,9 @@ bool LayoutTextTest( const LayoutTextData& data )
                    textModel,
                    metrics,
                    false,
-                   data.wrapMode );
+                   data.wrapMode,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   Vector<LineRun>& lines = textModel->mVisualModel->mLines;
 
@@ -157,7 +159,7 @@ int UtcDaliTextHyphenWrapping(void)
   Vector<FontDescriptionRun> fontDescriptionRuns;
   fontDescriptionRuns.PushBack( fontDescriptionRun1 );
   Size textArea(65.0f, 200.f);
-  
+
   LineRun line1 =
   {
     { 0u, 5u },
@@ -184,7 +186,7 @@ int UtcDaliTextHyphenWrapping(void)
     false,
     false
   };
-  
+
   Vector<LineRun> lines;
   lines.PushBack( line1 );
   lines.PushBack( line2 );
@@ -237,7 +239,7 @@ int UtcDaliTextMixedWrapping(void)
   Vector<FontDescriptionRun> fontDescriptionRuns;
   fontDescriptionRuns.PushBack( fontDescriptionRun1 );
   Size textArea(72.0f, 200.f);
-  
+
   LineRun line1 =
   {
     { 0u, 3u },
@@ -277,7 +279,7 @@ int UtcDaliTextMixedWrapping(void)
     false,
     false
   };
-  
+
   Vector<LineRun> lines;
   lines.PushBack( line1 );
   lines.PushBack( line2 );
index ed8d620..f670d49 100755 (executable)
@@ -41,21 +41,22 @@ const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
 
 struct LayoutTextData
 {
-  std::string          description;
-  std::string          text;
-  Size                 textArea;
-  unsigned int         numberOfFonts;
-  FontDescriptionRun*  fontDescriptions;
-  Size                 layoutSize;
-  unsigned int         totalNumberOfGlyphs;
-  float*               positions;
-  unsigned int         numberOfLines;
-  LineRun*             lines;
-  Layout::Engine::Type layout;
-  unsigned int         startIndex;
-  unsigned int         numberOfGlyphs;
-  bool                 ellipsis:1;
-  bool                 updated:1;
+  std::string                                       description;
+  std::string                                       text;
+  Size                                              textArea;
+  unsigned int                                      numberOfFonts;
+  FontDescriptionRun*                               fontDescriptions;
+  Size                                              layoutSize;
+  unsigned int                                      totalNumberOfGlyphs;
+  float*                                            positions;
+  unsigned int                                      numberOfLines;
+  LineRun*                                          lines;
+  Layout::Engine::Type                              layout;
+  unsigned int                                      startIndex;
+  unsigned int                                      numberOfGlyphs;
+  bool                                              ellipsis:1;
+  DevelText::EllipsisPosition::Type                 ellipsisPosition;
+  bool                                              updated:1;
 };
 
 void Print( const LineRun& line )
@@ -109,7 +110,9 @@ bool LayoutTextTest( const LayoutTextData& data )
                    textModel,
                    metrics,
                    false,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -179,7 +182,8 @@ bool LayoutTextTest( const LayoutTextData& data )
   const bool updated = engine.LayoutText( layoutParameters,
                                           layoutSize,
                                           data.ellipsis,
-                                          isAutoScroll );
+                                          isAutoScroll,
+                                          data.ellipsisPosition );
 
   // 4) Compare the results.
 
@@ -364,7 +368,9 @@ bool AlignTest( const AlignData& data )
                    textModel,
                    metrics,
                    false,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -501,6 +507,7 @@ int UtcDaliTextLayoutNoText(void)
     0u,
     0u,
     false,
+    DevelText::EllipsisPosition::END,
     false
   };
 
@@ -555,6 +562,7 @@ int UtcDaliTextLayoutSmallTextArea01(void)
     0u,
     11u,
     false,
+    DevelText::EllipsisPosition::END,
     false
   };
 
@@ -626,6 +634,7 @@ int UtcDaliTextLayoutSmallTextArea02(void)
     0u,
     11u,
     false,
+    DevelText::EllipsisPosition::END,
     true
   };
 
@@ -774,6 +783,7 @@ int UtcDaliTextLayoutMultilineText01(void)
     0u,
     48u,
     false,
+    DevelText::EllipsisPosition::END,
     true
   };
 
@@ -988,6 +998,7 @@ int UtcDaliTextLayoutMultilineText02(void)
     0u,
     55u,
     false,
+    DevelText::EllipsisPosition::END,
     true
   };
 
@@ -1092,6 +1103,7 @@ int UtcDaliTextLayoutMultilineText03(void)
     0u,
     29u,
     false,
+    DevelText::EllipsisPosition::END,
     true
   };
 
@@ -1179,6 +1191,7 @@ int UtcDaliTextLayoutMultilineText04(void)
     0u,
     13u,
     false,
+    DevelText::EllipsisPosition::END,
     true
   };
 
@@ -1295,6 +1308,7 @@ int UtcDaliTextLayoutMultilineText05(void)
     0u,
     17u,
     false,
+    DevelText::EllipsisPosition::END,
     true
   };
 
@@ -1383,6 +1397,7 @@ int UtcDaliTextLayoutMultilineText06(void)
     0u,
     10u,
     false,
+    DevelText::EllipsisPosition::END,
     true
   };
 
@@ -1486,6 +1501,7 @@ int UtcDaliTextLayoutMultilineText07(void)
     0u,
     9u,
     false,
+    DevelText::EllipsisPosition::END,
     true
   };
 
@@ -2061,6 +2077,7 @@ int UtcDaliTextUpdateLayout01(void)
     0u,
     64u,
     false,
+    DevelText::EllipsisPosition::END,
     true
   };
 
@@ -2636,6 +2653,7 @@ int UtcDaliTextUpdateLayout02(void)
     64u,
     64u,
     false,
+    DevelText::EllipsisPosition::END,
     true
   };
 
@@ -3211,6 +3229,7 @@ int UtcDaliTextUpdateLayout03(void)
     128u,
     64u,
     false,
+    DevelText::EllipsisPosition::END,
     true
   };
 
@@ -3288,6 +3307,7 @@ int UtcDaliTextLayoutEllipsis01(void)
     0u,
     51u,
     true,
+    DevelText::EllipsisPosition::END,
     true
   };
 
@@ -3380,6 +3400,7 @@ int UtcDaliTextLayoutEllipsis02(void)
     0u,
     51u,
     true,
+    DevelText::EllipsisPosition::END,
     true
   };
 
@@ -3523,6 +3544,7 @@ int UtcDaliTextLayoutEllipsis03(void)
     0u,
     72u,
     true,
+    DevelText::EllipsisPosition::END,
     true
   };
 
@@ -3681,6 +3703,7 @@ int UtcDaliTextLayoutEllipsis04(void)
     0u,
     72u,
     true,
+    DevelText::EllipsisPosition::END,
     true
   };
 
@@ -3756,6 +3779,7 @@ int UtcDaliTextLayoutEllipsis05(void)
     0u,
     11u,
     true,
+    DevelText::EllipsisPosition::END,
     true
   };
 
@@ -5377,6 +5401,7 @@ int UtcDaliTextLayoutGetGlyphMetrics(void)
       0u,
       1u,
       false,
+      DevelText::EllipsisPosition::END,
       true
     },
     {
@@ -5394,6 +5419,7 @@ int UtcDaliTextLayoutGetGlyphMetrics(void)
       0u,
       2u,
       false,
+      DevelText::EllipsisPosition::END,
       true
     },
    {
@@ -5411,6 +5437,7 @@ int UtcDaliTextLayoutGetGlyphMetrics(void)
       0u,
       2u,
       false,
+      DevelText::EllipsisPosition::END,
       true
     }
   };
index 52c8808..8c056dd 100755 (executable)
@@ -141,7 +141,9 @@ bool ShapeInfoTest( const ShapeInfoData& data )
                    textModel,
                    metrics,
                    false,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
index fc4f9ac..b9de8c1 100755 (executable)
@@ -604,10 +604,10 @@ int UtcDaliTextViewModelElideText02(void)
   float positions01[] = { 0.f, 8.f, 16.f, 26.f, 34.f, 43.f, 47.f, 58.f, 64.0f };
 
   Size textSize02( 80.f, 100.f );
-  float positions02[] = { 69.f, 63.f, 58.f, 50.f, 45.f, 41.f, 32.f, 23.f, 9.f };
+  float positions02[] = { 69.f, 63.f, 58.f, 50.f, 45.f, 41.f, 32.f, 23.f, 5.f };
 
   Size textSize03( 80.f, 100.f );
-  float positions03[] = { 54.f, 47.f, 44.f, 41.f, 36.f, 29.f, 25.f, 20.f, 13.f, 8.f, 4.f, 6.f };
+  float positions03[] = { 72.f, 65.f, 61.f, 59.f, 53.f, 47.f, 43.f, 38.f, 30.f, 25.f, 21.f, 7.f };
 
   Size textSize04( 80.f, 10.f );
   float positions04[] = { 2.f };
index 77075b5..7cf4084 100755 (executable)
@@ -284,6 +284,40 @@ int UtcDaliTextFieldBackgroundTag(void)
   END_TEST;
 }
 
+int UtcDaliToolkitTextFieldEllipsisInternalAPIs(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextFieldEllipsisInternalAPIs ");
+  TextField textField = TextField::New();
+
+  Toolkit::Internal::TextField& textFieldImpl = GetImpl( textField );
+  Text::ViewInterface& view = textFieldImpl.GetTextController()->GetView();
+
+  tet_infoline(" UtcDaliToolkitTextFieldEllipsisInternalAPIs - ELLIPSIS Disabled");
+  textField.SetProperty(DevelTextField::Property::ELLIPSIS, false);
+  DALI_TEST_EQUALS( textField.GetProperty< bool >( DevelTextField::Property::ELLIPSIS ), false, TEST_LOCATION );
+  DALI_TEST_CHECK(!(view.IsTextElideEnabled()));
+
+  tet_infoline(" UtcDaliToolkitTextFieldEllipsisInternalAPIs - ELLIPSIS Enabled");
+  textField.SetProperty(DevelTextField::Property::ELLIPSIS, true);
+  DALI_TEST_EQUALS( textField.GetProperty< bool >( DevelTextField::Property::ELLIPSIS ), true, TEST_LOCATION );
+  DALI_TEST_CHECK(view.IsTextElideEnabled());
+
+  tet_infoline(" UtcDaliToolkitTextFieldEllipsisInternalAPIs - GetStartIndexOfElidedGlyphs Default");
+  DALI_TEST_EQUALS( view.GetStartIndexOfElidedGlyphs(), 0u, TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextFieldEllipsisInternalAPIs - GetEndIndexOfElidedGlyphs Default");
+  DALI_TEST_EQUALS( view.GetEndIndexOfElidedGlyphs(), 0u, TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextFieldEllipsisInternalAPIs - GetFirstMiddleIndexOfElidedGlyphs Default");
+  DALI_TEST_EQUALS( view.GetFirstMiddleIndexOfElidedGlyphs(), 0u, TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextFieldEllipsisInternalAPIs - GetSecondMiddleIndexOfElidedGlyphs Default");
+  DALI_TEST_EQUALS( view.GetSecondMiddleIndexOfElidedGlyphs(), 0u, TEST_LOCATION );
+
+
+  END_TEST;
+}
 int UtcDaliTextFieldTextWithSpan(void)
 {
   ToolkitTestApplication application;
index e8a3996..b72dcb4 100755 (executable)
@@ -24,6 +24,8 @@
 #include <dali-toolkit/internal/controls/text-controls/text-label-impl.h>
 #include <dali-toolkit/internal/text/text-controller.h>
 #include <dali-toolkit/internal/text/text-controller-impl.h>
+#include <dali-toolkit/internal/text/rendering/text-typesetter.h>
+#include <dali-toolkit/internal/text/rendering/view-model.h>
 
 using namespace Dali;
 using namespace Toolkit;
@@ -99,6 +101,62 @@ int UtcDaliTextLabelBackgroundTag(void)
   END_TEST;
 }
 
+int UtcDaliToolkitTextlabelEllipsisInternalAPIs(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisInternalAPIs ");
+  TextLabel textLabel = TextLabel::New();
+
+  Toolkit::Internal::TextLabel& textLabelImpl = GetImpl( textLabel );
+  const ModelInterface* const textModel = textLabelImpl.GetTextController()->GetTextModel();
+
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisInternalAPIs - ELLIPSIS Disabled");
+  textLabel.SetProperty(DevelTextLabel::Property::ELLIPSIS, false);
+  DALI_TEST_EQUALS( textLabel.GetProperty< bool >( DevelTextLabel::Property::ELLIPSIS ), false, TEST_LOCATION );
+  DALI_TEST_CHECK(!(textModel->IsTextElideEnabled()));
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisInternalAPIs - ELLIPSIS Enabled");
+  textLabel.SetProperty(DevelTextLabel::Property::ELLIPSIS, true);
+  DALI_TEST_EQUALS( textLabel.GetProperty< bool >( DevelTextLabel::Property::ELLIPSIS ), true, TEST_LOCATION );
+  DALI_TEST_CHECK(textModel->IsTextElideEnabled());
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisInternalAPIs - GetStartIndexOfElidedGlyphs Default");
+  DALI_TEST_EQUALS( textModel->GetStartIndexOfElidedGlyphs(), 0u, TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisInternalAPIs - GetEndIndexOfElidedGlyphs Default");
+  DALI_TEST_EQUALS( textModel->GetEndIndexOfElidedGlyphs(), 0u, TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisInternalAPIs - GetFirstMiddleIndexOfElidedGlyphs Default");
+  DALI_TEST_EQUALS( textModel->GetFirstMiddleIndexOfElidedGlyphs(), 0u, TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisInternalAPIs - GetSecondMiddleIndexOfElidedGlyphs Default");
+  DALI_TEST_EQUALS( textModel->GetSecondMiddleIndexOfElidedGlyphs(), 0u, TEST_LOCATION );
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr typesetter = Typesetter::New( textModel );
+  DALI_TEST_CHECK(typesetter);
+
+  // Tests the view model has been created.
+  ViewModel* model = typesetter->GetViewModel();
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisInternalAPIs - IsTextElideEnabled ViewModel");
+  DALI_TEST_CHECK(model->IsTextElideEnabled());
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisInternalAPIs - GetStartIndexOfElidedGlyphs ViewModel");
+  DALI_TEST_EQUALS( model->GetStartIndexOfElidedGlyphs(), 0u, TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisInternalAPIs - GetEndIndexOfElidedGlyphs ViewModel");
+  DALI_TEST_EQUALS( model->GetEndIndexOfElidedGlyphs(), 0u, TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisInternalAPIs - GetFirstMiddleIndexOfElidedGlyphs ViewModel");
+  DALI_TEST_EQUALS( model->GetFirstMiddleIndexOfElidedGlyphs(), 0u, TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisInternalAPIs - GetSecondMiddleIndexOfElidedGlyphs ViewModel");
+  DALI_TEST_EQUALS( model->GetSecondMiddleIndexOfElidedGlyphs(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
 int UtcDaliTextLabelTextWithSpan(void)
 {
   ToolkitTestApplication application;
index 43157ff..2453771 100644 (file)
@@ -80,7 +80,9 @@ bool SetGlyphsPerCharacterTest( const SetGlyphsPerCharacterData& data )
                    textModel,
                    metrics,
                    false,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -165,7 +167,9 @@ bool SetCharacterToGlyphTest( const SetCharacterToGlyphData& data )
                    textModel,
                    metrics,
                    false,
-                   LineWrap::WORD );
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
index ba8e3d8..b518743 100644 (file)
@@ -3855,4 +3855,64 @@ int UtcDaliTextEditorHyphenWrapMode(void)
   DALI_TEST_EQUALS( lineCount, 3, TEST_LOCATION );
 
   END_TEST;
+}
+
+int UtcDaliToolkitTextEditorEllipsisPositionProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextEditorEllipsisPositionProperty ");
+  TextEditor textEditor = TextEditor::New();
+
+  tet_infoline(" UtcDaliToolkitTextEditorEllipsisPositionProperty - Default is END");
+  DALI_TEST_EQUALS( textEditor.GetProperty< int >( DevelTextEditor::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::END ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextEditorEllipsisPositionProperty - Change to START");
+  textEditor.SetProperty(DevelTextEditor::Property::ELLIPSIS_POSITION, DevelText::EllipsisPosition::START);
+  DALI_TEST_EQUALS( textEditor.GetProperty< int >( DevelTextEditor::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::START ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextEditorEllipsisPositionProperty - Change to MIDDLE");
+  textEditor.SetProperty(DevelTextEditor::Property::ELLIPSIS_POSITION, DevelText::EllipsisPosition::MIDDLE);
+  DALI_TEST_EQUALS( textEditor.GetProperty< int >( DevelTextEditor::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::MIDDLE ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextEditorEllipsisPositionProperty - Change to END");
+  textEditor.SetProperty(DevelTextEditor::Property::ELLIPSIS_POSITION, DevelText::EllipsisPosition::END);
+  DALI_TEST_EQUALS( textEditor.GetProperty< int >( DevelTextEditor::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::END ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextEditorEllipsisPositionProperty - Change to START using integer");
+  textEditor.SetProperty(DevelTextEditor::Property::ELLIPSIS_POSITION, 1);
+  DALI_TEST_EQUALS( textEditor.GetProperty< int >( DevelTextEditor::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::START ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextEditorEllipsisPositionProperty - Change to MIDDLE using integer");
+  textEditor.SetProperty(DevelTextEditor::Property::ELLIPSIS_POSITION, 2);
+  DALI_TEST_EQUALS( textEditor.GetProperty< int >( DevelTextEditor::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::MIDDLE ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextEditorEllipsisPositionProperty - Change to END using integer");
+  textEditor.SetProperty(DevelTextEditor::Property::ELLIPSIS_POSITION, 0);
+  DALI_TEST_EQUALS( textEditor.GetProperty< int >( DevelTextEditor::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::END ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to START using string - uppercase");
+  textEditor.SetProperty(DevelTextEditor::Property::ELLIPSIS_POSITION, "START");
+  DALI_TEST_EQUALS( textEditor.GetProperty< int >( DevelTextEditor::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::START ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to MIDDLE using string - uppercase");
+  textEditor.SetProperty(DevelTextEditor::Property::ELLIPSIS_POSITION, "MIDDLE");
+  DALI_TEST_EQUALS( textEditor.GetProperty< int >( DevelTextEditor::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::MIDDLE ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to END using string - uppercase");
+  textEditor.SetProperty(DevelTextEditor::Property::ELLIPSIS_POSITION, "END");
+  DALI_TEST_EQUALS( textEditor.GetProperty< int >( DevelTextEditor::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::END ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to START using string - lowercase");
+  textEditor.SetProperty(DevelTextEditor::Property::ELLIPSIS_POSITION, "start");
+  DALI_TEST_EQUALS( textEditor.GetProperty< int >( DevelTextEditor::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::START ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to MIDDLE using string - lowercase");
+  textEditor.SetProperty(DevelTextEditor::Property::ELLIPSIS_POSITION, "middle");
+  DALI_TEST_EQUALS( textEditor.GetProperty< int >( DevelTextEditor::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::MIDDLE ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to END using string - lowercase");
+  textEditor.SetProperty(DevelTextEditor::Property::ELLIPSIS_POSITION, "end");
+  DALI_TEST_EQUALS( textEditor.GetProperty< int >( DevelTextEditor::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::END ), TEST_LOCATION );
+
+  END_TEST;
 }
\ No newline at end of file
index 3f78b20..f6e24e6 100644 (file)
@@ -30,6 +30,7 @@
 #include <dali-toolkit/devel-api/controls/text-controls/text-field-devel.h>
 #include <dali-toolkit/devel-api/text/rendering-backend.h>
 #include "toolkit-clipboard.h"
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
 
 using namespace Dali;
 using namespace Toolkit;
@@ -3790,4 +3791,64 @@ int UtcDaliTextFieldAtlasLimitationIsEnabledPerformanceCases(void)
   }
 
   END_TEST;
+}
+
+int UtcDaliToolkitTextFieldEllipsisPositionProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextFieldEllipsisPositionProperty ");
+  TextField textField = TextField::New();
+
+  tet_infoline(" UtcDaliToolkitTextFieldEllipsisPositionProperty - Default is END");
+  DALI_TEST_EQUALS( textField.GetProperty< int >( DevelTextField::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::END ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextFieldEllipsisPositionProperty - Change to START");
+  textField.SetProperty(DevelTextField::Property::ELLIPSIS_POSITION, DevelText::EllipsisPosition::START);
+  DALI_TEST_EQUALS( textField.GetProperty< int >( DevelTextField::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::START ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextFieldEllipsisPositionProperty - Change to MIDDLE");
+  textField.SetProperty(DevelTextField::Property::ELLIPSIS_POSITION, DevelText::EllipsisPosition::MIDDLE);
+  DALI_TEST_EQUALS( textField.GetProperty< int >( DevelTextField::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::MIDDLE ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextFieldEllipsisPositionProperty - Change to END");
+  textField.SetProperty(DevelTextField::Property::ELLIPSIS_POSITION, DevelText::EllipsisPosition::END);
+  DALI_TEST_EQUALS( textField.GetProperty< int >( DevelTextField::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::END ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextFieldEllipsisPositionProperty - Change to START using integer");
+  textField.SetProperty(DevelTextField::Property::ELLIPSIS_POSITION, 1);
+  DALI_TEST_EQUALS( textField.GetProperty< int >( DevelTextField::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::START ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextFieldEllipsisPositionProperty - Change to MIDDLE using integer");
+  textField.SetProperty(DevelTextField::Property::ELLIPSIS_POSITION, 2);
+  DALI_TEST_EQUALS( textField.GetProperty< int >( DevelTextField::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::MIDDLE ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextFieldEllipsisPositionProperty - Change to END using integer");
+  textField.SetProperty(DevelTextField::Property::ELLIPSIS_POSITION, 0);
+  DALI_TEST_EQUALS( textField.GetProperty< int >( DevelTextField::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::END ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to START using string - uppercase");
+  textField.SetProperty(DevelTextField::Property::ELLIPSIS_POSITION, "START");
+  DALI_TEST_EQUALS( textField.GetProperty< int >( DevelTextField::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::START ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to MIDDLE using string - uppercase");
+  textField.SetProperty(DevelTextField::Property::ELLIPSIS_POSITION, "MIDDLE");
+  DALI_TEST_EQUALS( textField.GetProperty< int >( DevelTextField::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::MIDDLE ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to END using string - uppercase");
+  textField.SetProperty(DevelTextField::Property::ELLIPSIS_POSITION, "END");
+  DALI_TEST_EQUALS( textField.GetProperty< int >( DevelTextField::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::END ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to START using string - lowercase");
+  textField.SetProperty(DevelTextField::Property::ELLIPSIS_POSITION, "start");
+  DALI_TEST_EQUALS( textField.GetProperty< int >( DevelTextField::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::START ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to MIDDLE using string - lowercase");
+  textField.SetProperty(DevelTextField::Property::ELLIPSIS_POSITION, "middle");
+  DALI_TEST_EQUALS( textField.GetProperty< int >( DevelTextField::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::MIDDLE ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to END using string - lowercase");
+  textField.SetProperty(DevelTextField::Property::ELLIPSIS_POSITION, "end");
+  DALI_TEST_EQUALS( textField.GetProperty< int >( DevelTextField::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::END ), TEST_LOCATION );
+
+  END_TEST;
 }
\ No newline at end of file
index f505faf..e91c2b8 100644 (file)
@@ -74,6 +74,8 @@ const char* const PROPERTY_NAME_ELLIPSIS = "ellipsis";
 const char* const PROPERTY_NAME_AUTO_SCROLL_LOOP_DELAY = "autoScrollLoopDelay";
 const char* const PROPERTY_NAME_FONT_SIZE_SCALE = "fontSizeScale";
 
+const char* const PROPERTY_NAME_ELLIPSIS_POSITION = "ellipsisPosition";
+
 const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
 const unsigned int EMOJI_FONT_SIZE = 3840u; // 60 * 64
 
@@ -341,6 +343,7 @@ int UtcDaliToolkitTextLabelGetPropertyP(void)
   DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_ELLIPSIS ) == TextLabel::Property::ELLIPSIS );
   DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_AUTO_SCROLL_LOOP_DELAY ) == TextLabel::Property::AUTO_SCROLL_LOOP_DELAY );
   DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_FONT_SIZE_SCALE ) == DevelTextLabel::Property::FONT_SIZE_SCALE );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_ELLIPSIS_POSITION ) == DevelTextLabel::Property::ELLIPSIS_POSITION );
 
   END_TEST;
 }
@@ -1929,4 +1932,65 @@ int utcDaliTextLabelGetHeightForWidthChangeLineCountWhenTextChanged(void)
 
 
   END_TEST;
+}
+
+int UtcDaliToolkitTextlabelEllipsisPositionProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty ");
+  TextLabel textLabel = TextLabel::New();
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Default is END");
+  DALI_TEST_EQUALS( textLabel.GetProperty< int >( DevelTextLabel::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::END ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to START");
+  textLabel.SetProperty(DevelTextLabel::Property::ELLIPSIS_POSITION, DevelText::EllipsisPosition::START);
+  DALI_TEST_EQUALS( textLabel.GetProperty< int >( DevelTextLabel::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::START ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to MIDDLE");
+  textLabel.SetProperty(DevelTextLabel::Property::ELLIPSIS_POSITION, DevelText::EllipsisPosition::MIDDLE);
+  DALI_TEST_EQUALS( textLabel.GetProperty< int >( DevelTextLabel::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::MIDDLE ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to END");
+  textLabel.SetProperty(DevelTextLabel::Property::ELLIPSIS_POSITION, DevelText::EllipsisPosition::END);
+  DALI_TEST_EQUALS( textLabel.GetProperty< int >( DevelTextLabel::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::END ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to START using integer");
+  textLabel.SetProperty(DevelTextLabel::Property::ELLIPSIS_POSITION, 1);
+  DALI_TEST_EQUALS( textLabel.GetProperty< int >( DevelTextLabel::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::START ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to MIDDLE using integer");
+  textLabel.SetProperty(DevelTextLabel::Property::ELLIPSIS_POSITION, 2);
+  DALI_TEST_EQUALS( textLabel.GetProperty< int >( DevelTextLabel::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::MIDDLE ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to END using integer");
+  textLabel.SetProperty(DevelTextLabel::Property::ELLIPSIS_POSITION, 0);
+  DALI_TEST_EQUALS( textLabel.GetProperty< int >( DevelTextLabel::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::END ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to START using string - uppercase");
+  textLabel.SetProperty(DevelTextLabel::Property::ELLIPSIS_POSITION, "START");
+  DALI_TEST_EQUALS( textLabel.GetProperty< int >( DevelTextLabel::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::START ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to MIDDLE using string - uppercase");
+  textLabel.SetProperty(DevelTextLabel::Property::ELLIPSIS_POSITION, "MIDDLE");
+  DALI_TEST_EQUALS( textLabel.GetProperty< int >( DevelTextLabel::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::MIDDLE ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to END using string - uppercase");
+  textLabel.SetProperty(DevelTextLabel::Property::ELLIPSIS_POSITION, "END");
+  DALI_TEST_EQUALS( textLabel.GetProperty< int >( DevelTextLabel::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::END ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to START using string - lowercase");
+  textLabel.SetProperty(DevelTextLabel::Property::ELLIPSIS_POSITION, "start");
+  DALI_TEST_EQUALS( textLabel.GetProperty< int >( DevelTextLabel::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::START ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to MIDDLE using string - lowercase");
+  textLabel.SetProperty(DevelTextLabel::Property::ELLIPSIS_POSITION, "middle");
+  DALI_TEST_EQUALS( textLabel.GetProperty< int >( DevelTextLabel::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::MIDDLE ), TEST_LOCATION );
+
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsisPositionProperty - Change to END using string - lowercase");
+  textLabel.SetProperty(DevelTextLabel::Property::ELLIPSIS_POSITION, "end");
+  DALI_TEST_EQUALS( textLabel.GetProperty< int >( DevelTextLabel::Property::ELLIPSIS_POSITION ), static_cast< int >( Toolkit::DevelText::EllipsisPosition::END ), TEST_LOCATION );
+
+
+  END_TEST;
 }
\ No newline at end of file
index fb96330..695ca1b 100644 (file)
@@ -253,6 +253,20 @@ enum Type
    * @endcode
    */
   INPUT_FILTER,
+
+  /**
+  * @brief Whether we should show the ellipsis if required.
+  * @details Name "ellipsis", type Property::BOOLEAN.
+  */
+  ELLIPSIS,
+
+  /**
+  * @brief The enumerations used to specify whether to position the ellipsis at the END, START or MIDDLE of the text.
+  * @details Name "EllipsisPosition", type [Type](@ref Dali::Toolkit::DevelText::EllipsisPosition::Type) (Property::INTEGER), or Property::STRING. Read/Write
+  * @note Default is EllipsisPosition::END.
+  * @see DevelText::EllipsisPosition
+  */
+  ELLIPSIS_POSITION,
 };
 
 } // namespace Property
index f9f13dd..377b606 100644 (file)
@@ -205,6 +205,14 @@ enum
    * @endcode
    */
   INPUT_FILTER,
+
+  /**
+  * @brief The enumerations used to specify whether to position the ellipsis at the END, START or MIDDLE of the text.
+  * @details Name "EllipsisPosition", type [Type](@ref Dali::Toolkit::DevelText::EllipsisPosition::Type) (Property::INTEGER), or Property::STRING. Read/Write
+  * @note Default is EllipsisPosition::END.
+  * @see DevelText::EllipsisPosition
+  */
+  ELLIPSIS_POSITION,
 };
 
 } // namespace Property
index eed77fd..ac0f30c 100644 (file)
@@ -155,6 +155,13 @@ enum Type
    */
   FONT_SIZE_SCALE,
 
+  /**
+  * @brief The enumerations used to specify whether to position the ellipsis at the END, START or MIDDLE of the text.
+  * @details Name "EllipsisPosition", type [Type](@ref Dali::Toolkit::DevelText::EllipsisPosition::Type) (Property::INTEGER), or Property::STRING. Read/Write
+  * @note Default is EllipsisPosition::END.
+  * @see DevelText::EllipsisPosition
+  */
+  ELLIPSIS_POSITION,
 };
 
 } // namespace Property
index 9eb668f..100d59e 100644 (file)
@@ -68,6 +68,83 @@ enum class MatchLayoutDirection
   CONTENTS // The text layout direction is determined by the text itself.
 };
 
+/**
+ * @brief Contains types which specify where the text is truncated and replaced by Ellipsis glyph.
+ *
+ * If the text cannot fit into layout size then truncate text and replace it by Ellipsis glyph.
+ *
+ * Ellipsis works after layouting text normally according to LineWrap mode.
+ *
+ * Ellipsis glyph is three dots "...".
+ *
+ * The Ellipsis property should be enabled.
+ *
+ *
+ * Example: "Hello here is test goodbye."
+ *
+ * Assume LineWrap is CHARACTER.
+ *
+ * EllipsisPosition::END type in single line, truncate tail of line then add Ellipsis:
+ * @code
+ * +-----------+
+ * |Hello he...|
+ * +-----------+
+ * @endcode
+ *
+ * EllipsisPosition::END type in multi-lines, truncate tail of the last appeared line then add Ellipsis:
+ * @code
+ * +-----------+
+ * |Hello here |
+ * |is test ...|
+ * +-----------+
+ * @endcode
+ *
+ * EllipsisPosition::START type in single line, truncate head of line then add Ellipsis:
+ * @code
+ * +-----------+
+ * |...goodbye.|
+ * +-----------+
+ * @endcode
+ *
+ * EllipsisPosition::START type in multi-lines, truncate head of the first appeared line then add Ellipsis:
+ * @code
+ * +-----------+
+ * |...test goo|
+ * |dbye.      |
+ * +-----------+
+ * @endcode
+ *
+ * EllipsisPosition::MIDDLE type in single line, truncate middle of line then add Ellipsis:
+ * @code
+ * +-----------+
+ * |Hell...bye.|
+ * +-----------+
+ * @endcode
+ *
+ * EllipsisPosition::MIDDLE type in multi-lines, truncate middle lines. In the end of the last appeared line before removed lines add Ellipsis:
+ * @code
+ * +-----------+
+ * |Hello he...|
+ * |dbye.      |
+ * +-----------+
+ * @endcode
+ *
+ */
+namespace EllipsisPosition
+{
+/**
+ * @brief Enumerations specifying where to position the ellipsis glyph.
+ * @see EllipsisPosition
+ */
+enum Type
+{
+  END = 0, ///< END position will truncate tail of text that exceeds the layout size then replace it by Ellipsis glyph in the end of the last appeared line.
+  START,   ///< START position will truncate head of text that exceeds the layout size then replace it by Ellipsis glyph in the start of the first appeared line. In multilines, the lines are removed from top until the text fit into layout height.
+  MIDDLE   ///< MIDDLE position will truncate middle of text that exceeds the layout size then replace it by Ellipsis glyph in the middle of line. In multilines, the lines are removed from middle until the text fit into layout height then add ellipsis glyph in the end of the last line appeared before removed lines.
+};
+
+} // namespace EllipsisPosition
+
 } // namespace DevelText
 
 } // namespace Toolkit
index 046d014..9609a3b 100644 (file)
@@ -978,6 +978,7 @@ Size LayoutText(const RendererParameters& textParameters, TextAbstraction::TextR
   const bool               isTextMirrored          = internalDataModel.isTextMirrored;
   const Vector<Character>& mirroredUtf32Characters = internalDataModel.mirroredUtf32Characters;
   const Length             numberOfCharacters      = internalDataModel.numberOfCharacters;
+  const auto               ellipsisPosition        = textModel->mEllipsisPosition;
 
   Layout::Type layout = Layout::SINGLELINE;
 
@@ -1053,7 +1054,8 @@ Size LayoutText(const RendererParameters& textParameters, TextAbstraction::TextR
   layoutEngine.LayoutText(layoutParameters,
                           newLayoutSize,
                           textParameters.ellipsisEnabled,
-                          isAutoScrollEnabled);
+                          isAutoScrollEnabled,
+                          ellipsisPosition);
 
   return newLayoutSize;
 }
index eb05cf1..f74a28d 100644 (file)
@@ -149,6 +149,8 @@ DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "grabHandleColor
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "enableGrabHandlePopup",                BOOLEAN,   ENABLE_GRAB_HANDLE_POPUP            )
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "inputMethodSettings",                  MAP,       INPUT_METHOD_SETTINGS               )
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "inputFilter",                          MAP,       INPUT_FILTER                        )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "ellipsis",                             BOOLEAN,   ELLIPSIS                            )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextEditor, "ellipsisPosition",                     INTEGER,   ELLIPSIS_POSITION                   )
 
 DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "textChanged",        SIGNAL_TEXT_CHANGED       )
 DALI_SIGNAL_REGISTRATION(Toolkit, TextEditor, "inputStyleChanged",  SIGNAL_INPUT_STYLE_CHANGED)
@@ -812,6 +814,24 @@ void TextEditor::SetProperty(BaseObject* object, Property::Index index, const Pr
         }
         break;
       }
+      case Toolkit::DevelTextEditor::Property::ELLIPSIS:
+      {
+        const bool ellipsis = value.Get<bool>();
+        DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p ELLIPSIS %d\n", impl.mController.Get(), ellipsis);
+
+        impl.mController->SetTextElideEnabled(ellipsis);
+        break;
+      }
+      case Toolkit::DevelTextEditor::Property::ELLIPSIS_POSITION:
+      {
+        DevelText::EllipsisPosition::Type ellipsisPositionType(static_cast<DevelText::EllipsisPosition::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
+        if(GetEllipsisPositionTypeEnumeration(value, ellipsisPositionType))
+        {
+          DALI_LOG_INFO(gLogFilter, Debug::General, "TextEditor %p EllipsisPosition::Type %d\n", impl.mController.Get(), ellipsisPositionType);
+          impl.mController->SetEllipsisPosition(ellipsisPositionType);
+        }
+        break;
+      }
     } // switch
   }   // texteditor
 }
@@ -1192,6 +1212,16 @@ Property::Value TextEditor::GetProperty(BaseObject* object, Property::Index inde
         value = map;
         break;
       }
+      case Toolkit::DevelTextEditor::Property::ELLIPSIS:
+      {
+        value = impl.mController->IsTextElideEnabled();
+        break;
+      }
+      case Toolkit::DevelTextEditor::Property::ELLIPSIS_POSITION:
+      {
+        value = impl.mController->GetEllipsisPosition();
+        break;
+      }
     } //switch
   }
 
index f98093e..2cce4d2 100644 (file)
@@ -138,6 +138,7 @@ DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextField, "fontSizeScale",
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextField, "primaryCursorPosition",            INTEGER,   PRIMARY_CURSOR_POSITION             )
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextField, "grabHandleColor",                  VECTOR4,   GRAB_HANDLE_COLOR                   )
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextField, "inputFilter",                      MAP,       INPUT_FILTER                        )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextField, "ellipsisPosition",                 INTEGER,   ELLIPSIS_POSITION                   )
 
 DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "textChanged",       SIGNAL_TEXT_CHANGED       )
 DALI_SIGNAL_REGISTRATION(Toolkit, TextField, "maxLengthReached",  SIGNAL_MAX_LENGTH_REACHED )
@@ -775,6 +776,16 @@ void TextField::SetProperty(BaseObject* object, Property::Index index, const Pro
         }
         break;
       }
+      case Toolkit::DevelTextField::Property::ELLIPSIS_POSITION:
+      {
+        DevelText::EllipsisPosition::Type ellipsisPositionType(static_cast<DevelText::EllipsisPosition::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
+        if(GetEllipsisPositionTypeEnumeration(value, ellipsisPositionType))
+        {
+          DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p EllipsisPosition::Type %d\n", impl.mController.Get(), ellipsisPositionType);
+          impl.mController->SetEllipsisPosition(ellipsisPositionType);
+        }
+        break;
+      }
     } // switch
   }   // textfield
 }
@@ -1137,6 +1148,11 @@ Property::Value TextField::GetProperty(BaseObject* object, Property::Index index
         value = map;
         break;
       }
+      case Toolkit::DevelTextField::Property::ELLIPSIS_POSITION:
+      {
+        value = impl.mController->GetEllipsisPosition();
+        break;
+      }
     } //switch
   }
 
index b6c02d7..263b879 100644 (file)
@@ -47,6 +47,7 @@
 #include <dali-toolkit/public-api/visuals/text-visual-properties.h>
 #include <dali-toolkit/public-api/visuals/visual-properties.h>
 
+// DEVEL INCLUDES
 #include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
 
 using namespace Dali::Toolkit::Text;
@@ -133,6 +134,7 @@ DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "textFit",
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "minLineSize",                  FLOAT,   MIN_LINE_SIZE                  )
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "renderingBackend",             INTEGER, RENDERING_BACKEND              )
 DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "fontSizeScale",                FLOAT,   FONT_SIZE_SCALE                )
+DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit,           TextLabel, "ellipsisPosition",             INTEGER, ELLIPSIS_POSITION              )
 
 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)
@@ -481,6 +483,16 @@ void TextLabel::SetProperty(BaseObject* object, Property::Index index, const Pro
         }
         break;
       }
+      case Toolkit::DevelTextLabel::Property::ELLIPSIS_POSITION:
+      {
+        DevelText::EllipsisPosition::Type ellipsisPositionType(static_cast<DevelText::EllipsisPosition::Type>(-1)); // Set to invalid value to ensure a valid mode does get set
+        if(GetEllipsisPositionTypeEnumeration(value, ellipsisPositionType))
+        {
+          DALI_LOG_INFO(gLogFilter, Debug::General, "TextLabel %p EllipsisPosition::Type %d\n", impl.mController.Get(), ellipsisPositionType);
+          impl.mController->SetEllipsisPosition(ellipsisPositionType);
+        }
+        break;
+      }
     }
 
     // Request relayout when text update is needed. It's necessary to call it
@@ -717,6 +729,11 @@ Property::Value TextLabel::GetProperty(BaseObject* object, Property::Index index
         value = impl.mController->GetFontSizeScale();
         break;
       }
+      case Toolkit::DevelTextLabel::Property::ELLIPSIS_POSITION:
+      {
+        value = impl.mController->GetEllipsisPosition();
+        break;
+      }
     }
   }
 
index 63a8017..bffc7ef 100644 (file)
@@ -32,10 +32,12 @@ namespace Text
  */
 struct BidirectionalLineInfoRun
 {
-  CharacterRun       characterRun;       ///< The initial character index within the whole text and the number of characters of the run.
-  CharacterIndex*    visualToLogicalMap; ///< Pointer to the visual to logical map table.
-  CharacterDirection direction : 1;      ///< Direction of the first character of the paragraph.
-  bool               isIdentity : 1;     ///< Whether the map is the identity.
+  CharacterRun       characterRun;                  ///< The initial character index within the whole text and the number of characters of the run. In case the line is splitted by MIDDLE Ellipsis, this for the first half of line.
+  CharacterIndex*    visualToLogicalMap;            ///< Pointer to the visual to logical map table. In case the line is splitted by MIDDLE Ellipsis, this for the first half of line.
+  CharacterRun       characterRunForSecondHalfLine; ///< The initial character index within the whole text and the number of characters of the run for the second half of line.
+  CharacterIndex*    visualToLogicalMapSecondHalf;  ///< Pointer to the visual to logical map table for the second half of line.
+  CharacterDirection direction : 1;                 ///< Direction of the first character of the paragraph.
+  bool               isIdentity : 1;                ///< Whether the map is the identity.
 };
 
 } // namespace Text
index 90e8caf..c469275 100644 (file)
@@ -147,6 +147,8 @@ void ReorderLine(const BidirectionalParagraphInfoRun& bidirectionalParagraphInfo
                  BidirectionalLineRunIndex            bidiLineIndex,
                  CharacterIndex                       startIndex,
                  Length                               numberOfCharacters,
+                 CharacterIndex                       startIndexInSecondHalfLine,
+                 Length                               numberOfCharactersInSecondHalfLine,
                  CharacterDirection                   direction)
 {
   // Handle to the bidirectional info module in text-abstraction.
@@ -159,10 +161,15 @@ void ReorderLine(const BidirectionalParagraphInfoRun& bidirectionalParagraphInfo
   lineInfoRun.direction                       = direction;
   lineInfoRun.isIdentity                      = true;
 
+  lineInfoRun.characterRunForSecondHalfLine.characterIndex     = startIndexInSecondHalfLine;
+  lineInfoRun.characterRunForSecondHalfLine.numberOfCharacters = numberOfCharactersInSecondHalfLine;
+
   // Allocate space for the conversion maps.
   // The memory is freed after the visual to logical to visual conversion tables are built in the logical model.
   lineInfoRun.visualToLogicalMap = reinterpret_cast<CharacterIndex*>(malloc(numberOfCharacters * sizeof(CharacterIndex)));
 
+  lineInfoRun.visualToLogicalMapSecondHalf = reinterpret_cast<CharacterIndex*>(malloc(numberOfCharactersInSecondHalfLine * sizeof(CharacterIndex)));
+
   if(nullptr != lineInfoRun.visualToLogicalMap)
   {
     // Reorders the line.
@@ -171,6 +178,11 @@ void ReorderLine(const BidirectionalParagraphInfoRun& bidirectionalParagraphInfo
                                  lineInfoRun.characterRun.numberOfCharacters,
                                  lineInfoRun.visualToLogicalMap);
 
+    bidirectionalSupport.Reorder(bidirectionalParagraphInfo.bidirectionalInfoIndex,
+                                 lineInfoRun.characterRunForSecondHalfLine.characterIndex - bidirectionalParagraphInfo.characterRun.characterIndex,
+                                 lineInfoRun.characterRunForSecondHalfLine.numberOfCharacters,
+                                 lineInfoRun.visualToLogicalMapSecondHalf);
+
     // For those LTR lines inside a bidirectional paragraph.
     // It will save to relayout the line after reordering.
     for(unsigned int i = 0; i < numberOfCharacters; ++i)
@@ -181,6 +193,15 @@ void ReorderLine(const BidirectionalParagraphInfoRun& bidirectionalParagraphInfo
         break;
       }
     }
+
+    for(unsigned int i = 0; i < numberOfCharactersInSecondHalfLine; ++i)
+    {
+      if(i != *(lineInfoRun.visualToLogicalMapSecondHalf + i))
+      {
+        lineInfoRun.isIdentity = false;
+        break;
+      }
+    }
   }
 
   // Push the run into the vector.
index 864f6a3..054f50d 100644 (file)
@@ -63,6 +63,8 @@ void SetBidirectionalInfo(const Vector<Character>&               text,
  * @param[in] bidiLineIndex Index to the line's bidirectional info.
  * @param[in] startIndex The character from where the bidirectional info is set.
  * @param[in] numberOfCharacters The number of characters.
+ * @param[in] startIndexInSecondHalfLine The character from where the bidirectional info is set for the second half of line..
+ * @param[in] numberOfCharactersInSecondHalfLine The number of characters for the second half of line..
  * @param[in] direction The direction of the line.
  */
 void ReorderLine(const BidirectionalParagraphInfoRun& bidirectionalParagraphInfo,
@@ -70,6 +72,8 @@ void ReorderLine(const BidirectionalParagraphInfoRun& bidirectionalParagraphInfo
                  BidirectionalLineRunIndex            bidiLineIndex,
                  CharacterIndex                       startIndex,
                  Length                               numberOfCharacters,
+                 CharacterIndex                       startIndexInSecondHalfLine,
+                 Length                               numberOfCharactersInSecondHalfLine,
                  CharacterDirection                   direction);
 
 /**
index 6baed98..077b598 100644 (file)
@@ -75,7 +75,13 @@ struct LineLayout
     previousAdvance{0.f},
     length{0.f},
     whiteSpaceLengthEndOfLine{0.f},
-    direction{LTR}
+    direction{LTR},
+    isSplitToTwoHalves(false),
+    glyphIndexInSecondHalfLine{0u},
+    characterIndexInSecondHalfLine{0u},
+    numberOfGlyphsInSecondHalfLine{0u},
+    numberOfCharactersInSecondHalfLine{0u}
+
   {
   }
 
@@ -85,13 +91,18 @@ struct LineLayout
 
   void Clear()
   {
-    glyphIndex         = 0u;
-    characterIndex     = 0u;
-    numberOfGlyphs     = 0u;
-    numberOfCharacters = 0u;
-    ascender           = -MAX_FLOAT;
-    descender          = MAX_FLOAT;
-    direction          = LTR;
+    glyphIndex                         = 0u;
+    characterIndex                     = 0u;
+    numberOfGlyphs                     = 0u;
+    numberOfCharacters                 = 0u;
+    ascender                           = -MAX_FLOAT;
+    descender                          = MAX_FLOAT;
+    direction                          = LTR;
+    isSplitToTwoHalves                 = false;
+    glyphIndexInSecondHalfLine         = 0u;
+    characterIndexInSecondHalfLine     = 0u;
+    numberOfGlyphsInSecondHalfLine     = 0u;
+    numberOfCharactersInSecondHalfLine = 0u;
   }
 
   GlyphIndex         glyphIndex;                ///< Index of the first glyph to be laid-out.
@@ -106,6 +117,12 @@ struct LineLayout
   float              length;                    ///< The current length of the line.
   float              whiteSpaceLengthEndOfLine; ///< The length of the white spaces at the end of the line.
   CharacterDirection direction;
+
+  bool           isSplitToTwoHalves;                 ///< Whether the second half is defined.
+  GlyphIndex     glyphIndexInSecondHalfLine;         ///< Index of the first glyph to be laid-out for the second half of line.
+  CharacterIndex characterIndexInSecondHalfLine;     ///< Index of the first character to be laid-out for the second half of line.
+  Length         numberOfGlyphsInSecondHalfLine;     ///< The number of glyph which fit in one line for the second half of line.
+  Length         numberOfCharactersInSecondHalfLine; ///< The number of characters which fit in one line for the second half of line.
 };
 
 struct LayoutBidiParameters
@@ -175,9 +192,11 @@ struct Engine::Impl
    *
    * @param[in,out] lineLayout The line layout.
    * @param[in] tmpLineLayout A temporary line layout.
+   * @param[in] isShifted Whether to shift first glyph and character indices.
    */
   void MergeLineLayout(LineLayout&       lineLayout,
-                       const LineLayout& tmpLineLayout)
+                       const LineLayout& tmpLineLayout,
+                       bool              isShifted)
   {
     lineLayout.numberOfCharacters += tmpLineLayout.numberOfCharacters;
     lineLayout.numberOfGlyphs += tmpLineLayout.numberOfGlyphs;
@@ -193,6 +212,19 @@ struct Engine::Impl
 
     // Sets the minimum descender.
     lineLayout.descender = std::min(lineLayout.descender, tmpLineLayout.descender);
+
+    // To handle cases START in ellipsis position when want to shift first glyph to let width fit.
+    if(isShifted)
+    {
+      lineLayout.glyphIndex     = tmpLineLayout.glyphIndex;
+      lineLayout.characterIndex = tmpLineLayout.characterIndex;
+    }
+
+    lineLayout.isSplitToTwoHalves                 = tmpLineLayout.isSplitToTwoHalves;
+    lineLayout.glyphIndexInSecondHalfLine         = tmpLineLayout.glyphIndexInSecondHalfLine;
+    lineLayout.characterIndexInSecondHalfLine     = tmpLineLayout.characterIndexInSecondHalfLine;
+    lineLayout.numberOfGlyphsInSecondHalfLine     = tmpLineLayout.numberOfGlyphsInSecondHalfLine;
+    lineLayout.numberOfCharactersInSecondHalfLine = tmpLineLayout.numberOfCharactersInSecondHalfLine;
   }
 
   void LayoutRightToLeft(const Parameters&               parameters,
@@ -200,6 +232,11 @@ struct Engine::Impl
                          float&                          length,
                          float&                          whiteSpaceLengthEndOfLine)
   {
+    // Travers characters in line then draw it form right to left by mapping index using visualToLogicalMap.
+    // When the line is spllited by MIDDLE ellipsis then travers the second half of line "characterRunForSecondHalfLine"
+    // then the first half of line "characterRun",
+    // Otherwise travers whole characters in"characterRun".
+
     const Character* const  textBuffer               = parameters.textModel->mLogicalModel->mText.Begin();
     const Length* const     charactersPerGlyphBuffer = parameters.textModel->mVisualModel->mCharactersPerGlyph.Begin();
     const GlyphInfo* const  glyphsBuffer             = parameters.textModel->mVisualModel->mGlyphs.Begin();
@@ -209,21 +246,62 @@ struct Engine::Impl
     const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
 
     CharacterIndex characterLogicalIndex = 0u;
-    CharacterIndex characterVisualIndex  = bidirectionalLineInfo.characterRun.characterIndex + *(bidirectionalLineInfo.visualToLogicalMap + characterLogicalIndex);
+    CharacterIndex characterVisualIndex  = 0u;
+
+    // If there are characters in the second half of Line then the first visual index mapped from visualToLogicalMapSecondHalf
+    // Otherwise maps the first visual index from visualToLogicalMap.
+    // This is to initialize the first visual index.
+    if(bidirectionalLineInfo.characterRunForSecondHalfLine.numberOfCharacters > 0u)
+    {
+      characterVisualIndex = bidirectionalLineInfo.characterRunForSecondHalfLine.characterIndex + *(bidirectionalLineInfo.visualToLogicalMapSecondHalf + characterLogicalIndex);
+    }
+    else
+    {
+      characterVisualIndex = bidirectionalLineInfo.characterRun.characterIndex + *(bidirectionalLineInfo.visualToLogicalMap + characterLogicalIndex);
+    }
+
+    bool extendedToSecondHalf = false; // Whether the logical index is extended to second half
 
     if(RTL == bidirectionalLineInfo.direction)
     {
-      while(TextAbstraction::IsWhiteSpace(*(textBuffer + characterVisualIndex)))
+      // If there are characters in the second half of Line.
+      if(bidirectionalLineInfo.characterRunForSecondHalfLine.numberOfCharacters > 0u)
       {
-        const GlyphInfo& glyphInfo = *(glyphsBuffer + *(charactersToGlyphsBuffer + characterVisualIndex));
+        // Keep adding the WhiteSpaces to the whiteSpaceLengthEndOfLine
+        while(TextAbstraction::IsWhiteSpace(*(textBuffer + characterVisualIndex)))
+        {
+          const GlyphInfo& glyphInfo = *(glyphsBuffer + *(charactersToGlyphsBuffer + characterVisualIndex));
 
-        whiteSpaceLengthEndOfLine += glyphInfo.advance;
+          whiteSpaceLengthEndOfLine += glyphInfo.advance;
 
-        ++characterLogicalIndex;
-        characterVisualIndex = bidirectionalLineInfo.characterRun.characterIndex + *(bidirectionalLineInfo.visualToLogicalMap + characterLogicalIndex);
+          ++characterLogicalIndex;
+          characterVisualIndex = bidirectionalLineInfo.characterRunForSecondHalfLine.characterIndex + *(bidirectionalLineInfo.visualToLogicalMapSecondHalf + characterLogicalIndex);
+        }
+      }
+
+      // If all characters in the second half of Line are WhiteSpaces.
+      // then continue adding the WhiteSpaces from the first hel of Line.
+      // Also this is valid when the line was not splitted.
+      if(characterLogicalIndex == bidirectionalLineInfo.characterRunForSecondHalfLine.numberOfCharacters)
+      {
+        extendedToSecondHalf  = true; // Whether the logical index is extended to second half
+        characterLogicalIndex = 0u;
+        characterVisualIndex  = bidirectionalLineInfo.characterRun.characterIndex + *(bidirectionalLineInfo.visualToLogicalMap + characterLogicalIndex);
+
+        // Keep adding the WhiteSpaces to the whiteSpaceLengthEndOfLine
+        while(TextAbstraction::IsWhiteSpace(*(textBuffer + characterVisualIndex)))
+        {
+          const GlyphInfo& glyphInfo = *(glyphsBuffer + *(charactersToGlyphsBuffer + characterVisualIndex));
+
+          whiteSpaceLengthEndOfLine += glyphInfo.advance;
+
+          ++characterLogicalIndex;
+          characterVisualIndex = bidirectionalLineInfo.characterRun.characterIndex + *(bidirectionalLineInfo.visualToLogicalMap + characterLogicalIndex);
+        }
       }
     }
 
+    // Here's the first index of character is not WhiteSpace
     const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex);
 
     // Check whether the first glyph comes from a character that is shaped in multiple glyphs.
@@ -241,6 +319,70 @@ struct Engine::Impl
     float penX = -glyphMetrics.xBearing + mCursorWidth + outlineWidth;
 
     // Traverses the characters of the right to left paragraph.
+    // Continue in the second half of line, because in it the first index of character that is not WhiteSpace.
+    if(!extendedToSecondHalf &&
+       bidirectionalLineInfo.characterRunForSecondHalfLine.numberOfCharacters > 0u)
+    {
+      for(; characterLogicalIndex < bidirectionalLineInfo.characterRunForSecondHalfLine.numberOfCharacters;)
+      {
+        // Convert the character in the logical order into the character in the visual order.
+        const CharacterIndex characterVisualIndex = bidirectionalLineInfo.characterRunForSecondHalfLine.characterIndex + *(bidirectionalLineInfo.visualToLogicalMapSecondHalf + characterLogicalIndex);
+        const bool           isWhiteSpace         = TextAbstraction::IsWhiteSpace(*(textBuffer + characterVisualIndex));
+
+        const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex);
+
+        // Check whether this glyph comes from a character that is shaped in multiple glyphs.
+        const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup(glyphIndex,
+                                                                      lastGlyphOfParagraphPlusOne,
+                                                                      charactersPerGlyphBuffer);
+
+        characterLogicalIndex += *(charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u);
+
+        GlyphMetrics glyphMetrics;
+        GetGlyphsMetrics(glyphIndex,
+                         numberOfGLyphsInGroup,
+                         glyphMetrics,
+                         glyphsBuffer,
+                         mMetrics);
+
+        if(isWhiteSpace)
+        {
+          // If glyph is WhiteSpace then:
+          // For RTL it is whitespace but not at endOfLine. Use "advance" to accumulate length and shift penX.
+          // the endOfLine in RTL was the headOfLine for layouting.
+          // But for LTR added it to the endOfLine and use "advance" to accumulate length.
+          if(RTL == bidirectionalLineInfo.direction)
+          {
+            length += glyphMetrics.advance;
+          }
+          else
+          {
+            whiteSpaceLengthEndOfLine += glyphMetrics.advance;
+          }
+          penX += glyphMetrics.advance;
+        }
+        else
+        {
+          // If glyph is not whiteSpace then:
+          // Reset endOfLine for LTR because there is a non-whiteSpace so the tail of line is not whiteSpaces
+          // Use "advance" and "interGlyphExtraAdvance" to shift penX.
+          // Set length to the maximum possible length, of the current glyph "xBearing" and "width" are shifted penX to length greater than current lenght.
+          // Otherwise the current length is maximum.
+          if(LTR == bidirectionalLineInfo.direction)
+          {
+            whiteSpaceLengthEndOfLine = 0.f;
+          }
+          length = std::max(length, penX + glyphMetrics.xBearing + glyphMetrics.width);
+          penX += (glyphMetrics.advance + parameters.interGlyphExtraAdvance);
+        }
+      }
+    }
+
+    // Continue traversing in the first half of line or in the whole line.
+    // If the second half of line was extended then continue from logical index in the first half of line
+    // Also this is valid when the line was not splitted and there were WhiteSpace.
+    // Otherwise start from first logical index in line.
+    characterLogicalIndex = extendedToSecondHalf ? characterLogicalIndex : 0u;
     for(; characterLogicalIndex < bidirectionalLineInfo.characterRun.numberOfCharacters;)
     {
       // Convert the character in the logical order into the character in the visual order.
@@ -265,6 +407,10 @@ struct Engine::Impl
 
       if(isWhiteSpace)
       {
+        // If glyph is WhiteSpace then:
+        // For RTL it is whitespace but not at endOfLine. Use "advance" to accumulate length and shift penX.
+        // the endOfLine in RTL was the headOfLine for layouting.
+        // But for LTR added it to the endOfLine and use "advance" to accumulate length.
         if(RTL == bidirectionalLineInfo.direction)
         {
           length += glyphMetrics.advance;
@@ -277,6 +423,11 @@ struct Engine::Impl
       }
       else
       {
+        // If glyph is not whiteSpace then:
+        // Reset endOfLine for LTR because there is a non-whiteSpace so the tail of line is not whiteSpaces
+        // Use "advance" and "interGlyphExtraAdvance" to shift penX.
+        // Set length to the maximum possible length, of the current glyph "xBearing" and "width" are shifted penX to length greater than current lenght.
+        // Otherwise the current length is maximum.
         if(LTR == bidirectionalLineInfo.direction)
         {
           whiteSpaceLengthEndOfLine = 0.f;
@@ -291,7 +442,8 @@ struct Engine::Impl
                          LayoutBidiParameters& bidiParameters,
                          const LineLayout&     currentLineLayout,
                          LineLayout&           lineLayout,
-                         bool                  breakInCharacters)
+                         bool                  breakInCharacters,
+                         bool                  enforceEllipsisInSingleLine)
   {
     const Length* const charactersPerGlyphBuffer = parameters.textModel->mVisualModel->mCharactersPerGlyph.Begin();
 
@@ -312,6 +464,8 @@ struct Engine::Impl
                   bidiParameters.bidiLineIndex,
                   lineLayout.characterIndex,
                   lineLayout.numberOfCharacters,
+                  lineLayout.characterIndexInSecondHalfLine,
+                  lineLayout.numberOfCharactersInSecondHalfLine,
                   bidiParameters.paragraphDirection);
 
       // Recalculate the length of the line and update the layout.
@@ -329,7 +483,7 @@ struct Engine::Impl
         lineLayout.whiteSpaceLengthEndOfLine = whiteSpaceLengthEndOfLine;
         if(!Equals(length, lineLayout.length))
         {
-          const bool isMultiline = mLayout == MULTI_LINE_BOX;
+          const bool isMultiline = (!enforceEllipsisInSingleLine) && (mLayout == MULTI_LINE_BOX);
 
           if(isMultiline && (length > parameters.boundingBox.width))
           {
@@ -403,6 +557,8 @@ struct Engine::Impl
                 bidiParameters.bidiLineIndex,
                 lineLayout.characterIndex,
                 lineLayout.numberOfCharacters,
+                lineLayout.characterIndexInSecondHalfLine,
+                lineLayout.numberOfCharactersInSecondHalfLine,
                 bidiParameters.paragraphDirection);
 
     const BidirectionalLineInfoRun& bidirectionalLineInfo = *(bidirectionalLinesInfo.Begin() + bidiParameters.bidiLineIndex);
@@ -430,11 +586,15 @@ struct Engine::Impl
    * @param[] bidiParameters Bidirectional info for the current line.
    * @param[out] lineLayout The line layout.
    * @param[in] completelyFill Whether to completely fill the line ( even if the last word exceeds the boundaries ).
+   * @param[in] ellipsisPosition Where is the location the text elide
    */
-  void GetLineLayoutForBox(const Parameters&     parameters,
-                           LayoutBidiParameters& bidiParameters,
-                           LineLayout&           lineLayout,
-                           bool                  completelyFill)
+  void GetLineLayoutForBox(const Parameters&                 parameters,
+                           LayoutBidiParameters&             bidiParameters,
+                           LineLayout&                       lineLayout,
+                           bool                              completelyFill,
+                           DevelText::EllipsisPosition::Type ellipsisPosition,
+                           bool                              enforceEllipsisInSingleLine,
+                           bool                              elideTextEnabled)
   {
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->GetLineLayoutForBox\n");
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  initial glyph index : %d\n", lineLayout.glyphIndex);
@@ -448,13 +608,15 @@ struct Engine::Impl
     const float  outlineWidth        = static_cast<float>(parameters.textModel->GetOutlineWidth());
     const Length totalNumberOfGlyphs = parameters.textModel->mVisualModel->mGlyphs.Count();
 
-    const bool isMultiline   = mLayout == MULTI_LINE_BOX;
+    const bool isMultiline   = !enforceEllipsisInSingleLine && (mLayout == MULTI_LINE_BOX);
     const bool isWordLaidOut = parameters.textModel->mLineWrapMode == Text::LineWrap::WORD ||
                                (parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
                                (parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED);
     const bool isHyphenMode = parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION;
     const bool isMixedMode  = parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED;
 
+    const bool isSplitToTwoHalves = elideTextEnabled && !isMultiline && ellipsisPosition == DevelText::EllipsisPosition::MIDDLE;
+
     // The last glyph to be laid-out.
     const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
 
@@ -467,6 +629,11 @@ struct Engine::Impl
                                                                   lastGlyphOfParagraphPlusOne,
                                                                   charactersPerGlyphBuffer);
 
+    float targetWidth    = parameters.boundingBox.width;
+    float widthFirstHalf = ((ellipsisPosition != DevelText::EllipsisPosition::MIDDLE) ? targetWidth : targetWidth - std::floor(targetWidth / 2));
+
+    bool isSecondHalf = false;
+
     GlyphMetrics glyphMetrics;
     GetGlyphsMetrics(lineLayout.glyphIndex,
                      numberOfGLyphsInGroup,
@@ -534,11 +701,22 @@ struct Engine::Impl
       // Get the line break info for the current character.
       const LineBreakInfo lineBreakInfo = hasCharacters ? *(lineBreakInfoBuffer + characterLastIndex) : TextAbstraction::LINE_NO_BREAK;
 
-      // Increase the number of characters.
-      tmpLineLayout.numberOfCharacters += charactersPerGlyph;
+      if(isSecondHalf)
+      {
+        // Increase the number of characters.
+        tmpLineLayout.numberOfCharactersInSecondHalfLine += charactersPerGlyph;
+
+        // Increase the number of glyphs.
+        tmpLineLayout.numberOfGlyphsInSecondHalfLine += numberOfGLyphsInGroup;
+      }
+      else
+      {
+        // Increase the number of characters.
+        tmpLineLayout.numberOfCharacters += charactersPerGlyph;
 
-      // Increase the number of glyphs.
-      tmpLineLayout.numberOfGlyphs += numberOfGLyphsInGroup;
+        // Increase the number of glyphs.
+        tmpLineLayout.numberOfGlyphs += numberOfGLyphsInGroup;
+      }
 
       // Check whether is a white space.
       const Character character    = *(textBuffer + characterFirstIndex);
@@ -568,9 +746,94 @@ struct Engine::Impl
         tmpLineLayout.whiteSpaceLengthEndOfLine = 0.f;
       }
 
+      if(isSplitToTwoHalves && (!isSecondHalf) &&
+         (tmpLineLayout.length + tmpLineLayout.whiteSpaceLengthEndOfLine > widthFirstHalf))
+      {
+        tmpLineLayout.numberOfCharacters -= charactersPerGlyph;
+        tmpLineLayout.numberOfGlyphs -= numberOfGLyphsInGroup;
+
+        tmpLineLayout.numberOfCharactersInSecondHalfLine += charactersPerGlyph;
+        tmpLineLayout.numberOfGlyphsInSecondHalfLine += numberOfGLyphsInGroup;
+
+        tmpLineLayout.glyphIndexInSecondHalfLine     = tmpLineLayout.glyphIndex + tmpLineLayout.numberOfGlyphs;
+        tmpLineLayout.characterIndexInSecondHalfLine = tmpLineLayout.characterIndex + tmpLineLayout.numberOfCharacters;
+
+        tmpLineLayout.isSplitToTwoHalves = isSecondHalf = true;
+      }
       // Check if the accumulated length fits in the width of the box.
-      if((completelyFill || isMultiline) && !isWhiteSpace &&
-         (tmpLineLayout.length > parameters.boundingBox.width))
+      if((ellipsisPosition == DevelText::EllipsisPosition::START ||
+          (ellipsisPosition == DevelText::EllipsisPosition::MIDDLE && isSecondHalf)) &&
+         completelyFill && !isMultiline &&
+         (tmpLineLayout.length + tmpLineLayout.whiteSpaceLengthEndOfLine > targetWidth))
+      {
+        GlyphIndex glyphIndexToRemove = isSecondHalf ? tmpLineLayout.glyphIndexInSecondHalfLine : tmpLineLayout.glyphIndex;
+
+        while(tmpLineLayout.length + tmpLineLayout.whiteSpaceLengthEndOfLine > targetWidth && glyphIndexToRemove < glyphIndex)
+        {
+          GlyphMetrics glyphMetrics;
+          GetGlyphsMetrics(glyphIndexToRemove,
+                           numberOfGLyphsInGroup,
+                           glyphMetrics,
+                           glyphsBuffer,
+                           mMetrics);
+
+          const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup(glyphIndexToRemove,
+                                                                        lastGlyphOfParagraphPlusOne,
+                                                                        charactersPerGlyphBuffer);
+
+          const Length         charactersPerGlyph  = *(charactersPerGlyphBuffer + glyphIndexToRemove + numberOfGLyphsInGroup - 1u);
+          const bool           hasCharacters       = charactersPerGlyph > 0u;
+          const CharacterIndex characterFirstIndex = *(glyphsToCharactersBuffer + glyphIndexToRemove);
+          const CharacterIndex characterLastIndex  = characterFirstIndex + (hasCharacters ? charactersPerGlyph - 1u : 0u);
+
+          // Check whether is a white space.
+          const Character character                = *(textBuffer + characterFirstIndex);
+          const bool      isRemovedGlyphWhiteSpace = TextAbstraction::IsWhiteSpace(character);
+
+          if(isSecondHalf)
+          {
+            // Decrease the number of characters for SecondHalf.
+            tmpLineLayout.numberOfCharactersInSecondHalfLine -= charactersPerGlyph;
+
+            // Decrease the number of glyphs for SecondHalf.
+            tmpLineLayout.numberOfGlyphsInSecondHalfLine -= numberOfGLyphsInGroup;
+          }
+          else
+          {
+            // Decrease the number of characters.
+            tmpLineLayout.numberOfCharacters -= charactersPerGlyph;
+
+            // Decrease the number of glyphs.
+            tmpLineLayout.numberOfGlyphs -= numberOfGLyphsInGroup;
+          }
+
+          if(isRemovedGlyphWhiteSpace)
+          {
+            tmpLineLayout.penX -= glyphMetrics.advance;
+            tmpLineLayout.length -= glyphMetrics.advance;
+          }
+          else
+          {
+            tmpLineLayout.penX -= (glyphMetrics.advance + parameters.interGlyphExtraAdvance);
+            tmpLineLayout.length -= (std::min(glyphMetrics.advance + parameters.interGlyphExtraAdvance, glyphMetrics.xBearing + glyphMetrics.width));
+          }
+
+          if(isSecondHalf)
+          {
+            tmpLineLayout.glyphIndexInSecondHalfLine += numberOfGLyphsInGroup;
+            tmpLineLayout.characterIndexInSecondHalfLine = characterLastIndex + 1u;
+            glyphIndexToRemove                           = tmpLineLayout.glyphIndexInSecondHalfLine;
+          }
+          else
+          {
+            tmpLineLayout.glyphIndex += numberOfGLyphsInGroup;
+            tmpLineLayout.characterIndex = characterLastIndex + 1u;
+            glyphIndexToRemove           = tmpLineLayout.glyphIndex;
+          }
+        }
+      }
+      else if((completelyFill || isMultiline) &&
+              (tmpLineLayout.length > targetWidth))
       {
         // Current word does not fit in the box's width.
         if(((oneHyphenLaidOut && isHyphenMode) ||
@@ -586,10 +849,18 @@ struct Engine::Impl
           DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  Break the word by character\n");
 
           // The word doesn't fit in the control's width. It needs to be split by character.
-          if(tmpLineLayout.numberOfGlyphs > 0u)
+          if(tmpLineLayout.numberOfGlyphs + tmpLineLayout.numberOfGlyphsInSecondHalfLine > 0u)
           {
-            tmpLineLayout.numberOfCharacters -= charactersPerGlyph;
-            tmpLineLayout.numberOfGlyphs -= numberOfGLyphsInGroup;
+            if(isSecondHalf)
+            {
+              tmpLineLayout.numberOfCharactersInSecondHalfLine -= charactersPerGlyph;
+              tmpLineLayout.numberOfGlyphsInSecondHalfLine -= numberOfGLyphsInGroup;
+            }
+            else
+            {
+              tmpLineLayout.numberOfCharacters -= charactersPerGlyph;
+              tmpLineLayout.numberOfGlyphs -= numberOfGLyphsInGroup;
+            }
 
             tmpLineLayout.penX                      = previousTmpPenX;
             tmpLineLayout.previousAdvance           = previousTmpAdvance;
@@ -597,8 +868,17 @@ struct Engine::Impl
             tmpLineLayout.whiteSpaceLengthEndOfLine = previousTmpWhiteSpaceLengthEndOfLine;
           }
 
-          // Add part of the word to the line layout.
-          MergeLineLayout(lineLayout, tmpLineLayout);
+          if(ellipsisPosition == DevelText::EllipsisPosition::START && !isMultiline)
+          {
+            // Add part of the word to the line layout and shift the first glyph.
+            MergeLineLayout(lineLayout, tmpLineLayout, true);
+          }
+          else if(ellipsisPosition != DevelText::EllipsisPosition::START ||
+                  (ellipsisPosition == DevelText::EllipsisPosition::START && (!completelyFill)))
+          {
+            // Add part of the word to the line layout.
+            MergeLineLayout(lineLayout, tmpLineLayout, false);
+          }
         }
         else
         {
@@ -614,7 +894,8 @@ struct Engine::Impl
                             bidiParameters,
                             lineLayout,
                             lineLayout,
-                            true);
+                            true,
+                            enforceEllipsisInSingleLine);
         }
 
         return;
@@ -625,8 +906,17 @@ struct Engine::Impl
       {
         LineLayout currentLineLayout = lineLayout;
         oneHyphenLaidOut             = false;
-        // Must break the line. Update the line layout and return.
-        MergeLineLayout(lineLayout, tmpLineLayout);
+
+        if(ellipsisPosition == DevelText::EllipsisPosition::START && !isMultiline)
+        {
+          // Must break the line. Update the line layout, shift the first glyph and return.
+          MergeLineLayout(lineLayout, tmpLineLayout, true);
+        }
+        else
+        {
+          // Must break the line. Update the line layout and return.
+          MergeLineLayout(lineLayout, tmpLineLayout, false);
+        }
 
         // Reorder the RTL line.
         if(bidiParameters.isBidirectional)
@@ -635,7 +925,8 @@ struct Engine::Impl
                             bidiParameters,
                             currentLineLayout,
                             lineLayout,
-                            false);
+                            false,
+                            enforceEllipsisInSingleLine);
         }
 
         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  Must break\n");
@@ -653,7 +944,7 @@ struct Engine::Impl
 
         // Current glyph is the last one of the current word.
         // Add the temporal layout to the current one.
-        MergeLineLayout(lineLayout, tmpLineLayout);
+        MergeLineLayout(lineLayout, tmpLineLayout, false);
 
         tmpLineLayout.Clear();
       }
@@ -670,7 +961,7 @@ struct Engine::Impl
 
         mMetrics->GetGlyphMetrics(&hyphenGlyph, 1);
 
-        if((tmpLineLayout.length + hyphenGlyph.width) <= parameters.boundingBox.width)
+        if((tmpLineLayout.length + hyphenGlyph.width) <= targetWidth)
         {
           hyphenIndex      = glyphIndex;
           oneHyphenLaidOut = true;
@@ -679,7 +970,7 @@ struct Engine::Impl
 
           // Current glyph is the last one of the current word hyphen.
           // Add the temporal layout to the current one.
-          MergeLineLayout(lineLayout, tmpLineLayout);
+          MergeLineLayout(lineLayout, tmpLineLayout, false);
 
           tmpLineLayout.Clear();
         }
@@ -691,31 +982,54 @@ struct Engine::Impl
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n");
   }
 
-  void SetGlyphPositions(const GlyphInfo* const glyphsBuffer,
-                         Length                 numberOfGlyphs,
-                         float                  outlineWidth,
-                         float                  interGlyphExtraAdvance,
-                         Vector2*               glyphPositionsBuffer)
+  void SetGlyphPositions(const Parameters& layoutParameters,
+                         Vector2*          glyphPositionsBuffer,
+                         const LineLayout& layout)
   {
     // Traverse the glyphs and set the positions.
 
+    const GlyphInfo* const glyphsBuffer           = layoutParameters.textModel->mVisualModel->mGlyphs.Begin();
+    const float            outlineWidth           = static_cast<float>(layoutParameters.textModel->GetOutlineWidth());
+    const Length           numberOfGlyphs         = layout.numberOfGlyphs;
+    const float            interGlyphExtraAdvance = layoutParameters.interGlyphExtraAdvance;
+
+    const GlyphIndex startIndexForGlyph          = layout.glyphIndex;
+    const GlyphIndex startIndexForGlyphPositions = startIndexForGlyph - layoutParameters.startGlyphIndex;
+
     // Check if the x bearing of the first character is negative.
     // If it has a negative x bearing, it will exceed the boundaries of the actor,
     // so the penX position needs to be moved to the right.
-
-    const GlyphInfo& glyph = *glyphsBuffer;
-    float            penX  = -glyph.xBearing + mCursorWidth + outlineWidth;
+    const GlyphInfo& glyph = *(glyphsBuffer + startIndexForGlyph);
+    float            penX  = -glyph.xBearing + mCursorWidth + outlineWidth; //
 
     for(GlyphIndex i = 0u; i < numberOfGlyphs; ++i)
     {
-      const GlyphInfo& glyph    = *(glyphsBuffer + i);
-      Vector2&         position = *(glyphPositionsBuffer + i);
+      const GlyphInfo& glyph    = *(glyphsBuffer + startIndexForGlyph + i);
+      Vector2&         position = *(glyphPositionsBuffer + startIndexForGlyphPositions + i);
 
       position.x = penX + glyph.xBearing;
       position.y = -glyph.yBearing;
 
       penX += (glyph.advance + interGlyphExtraAdvance);
     }
+
+    if(layout.isSplitToTwoHalves)
+    {
+      const GlyphIndex startIndexForGlyphInSecondHalf         = layout.glyphIndexInSecondHalfLine;
+      const Length     numberOfGlyphsInSecondHalfLine         = layout.numberOfGlyphsInSecondHalfLine;
+      const GlyphIndex startIndexForGlyphPositionsnSecondHalf = layout.glyphIndexInSecondHalfLine - layoutParameters.startGlyphIndex;
+
+      for(GlyphIndex i = 0u; i < numberOfGlyphsInSecondHalfLine; ++i)
+      {
+        const GlyphInfo& glyph    = *(glyphsBuffer + startIndexForGlyphInSecondHalf + i);
+        Vector2&         position = *(glyphPositionsBuffer + startIndexForGlyphPositionsnSecondHalf + i);
+
+        position.x = penX + glyph.xBearing;
+        position.y = -glyph.yBearing;
+
+        penX += (glyph.advance + interGlyphExtraAdvance);
+      }
+    }
   }
 
   void SetGlyphPositions(const Parameters&     layoutParameters,
@@ -730,22 +1044,49 @@ struct Engine::Impl
     const Length* const             glyphsPerCharacterBuffer = layoutParameters.textModel->mVisualModel->mGlyphsPerCharacter.Begin();
 
     CharacterIndex characterLogicalIndex = 0u;
-    CharacterIndex characterVisualIndex  = bidiLine.characterRun.characterIndex + *(bidiLine.visualToLogicalMap + characterLogicalIndex);
+    CharacterIndex characterVisualIndex  = bidiLine.characterRunForSecondHalfLine.characterIndex + *(bidiLine.visualToLogicalMapSecondHalf + characterLogicalIndex);
+    bool           extendedToSecondHalf  = false; // Whether the logical index is extended to second half
 
     float penX = 0.f;
-    while(TextAbstraction::IsWhiteSpace(*(textBuffer + characterVisualIndex)))
+
+    if(layout.isSplitToTwoHalves)
     {
-      const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex);
-      const GlyphInfo& glyph      = *(glyphsBuffer + glyphIndex);
+      while(TextAbstraction::IsWhiteSpace(*(textBuffer + characterVisualIndex)))
+      {
+        const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex);
+        const GlyphInfo& glyph      = *(glyphsBuffer + glyphIndex);
 
-      Vector2& position = *(glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex);
-      position.x        = penX;
-      position.y        = -glyph.yBearing;
+        Vector2& position = *(glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex);
+        position.x        = penX;
+        position.y        = -glyph.yBearing;
 
-      penX += glyph.advance;
+        penX += glyph.advance;
 
-      ++characterLogicalIndex;
-      characterVisualIndex = bidiLine.characterRun.characterIndex + *(bidiLine.visualToLogicalMap + characterLogicalIndex);
+        ++characterLogicalIndex;
+        characterVisualIndex = bidiLine.characterRun.characterIndex + *(bidiLine.visualToLogicalMap + characterLogicalIndex);
+      }
+    }
+
+    if(characterLogicalIndex == bidiLine.characterRunForSecondHalfLine.numberOfCharacters)
+    {
+      extendedToSecondHalf  = true;
+      characterLogicalIndex = 0u;
+      characterVisualIndex  = bidiLine.characterRun.characterIndex + *(bidiLine.visualToLogicalMap + characterLogicalIndex);
+
+      while(TextAbstraction::IsWhiteSpace(*(textBuffer + characterVisualIndex)))
+      {
+        const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex);
+        const GlyphInfo& glyph      = *(glyphsBuffer + glyphIndex);
+
+        Vector2& position = *(glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex);
+        position.x        = penX;
+        position.y        = -glyph.yBearing;
+
+        penX += glyph.advance;
+
+        ++characterLogicalIndex;
+        characterVisualIndex = bidiLine.characterRun.characterIndex + *(bidiLine.visualToLogicalMap + characterLogicalIndex);
+      }
     }
 
     const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex);
@@ -754,6 +1095,36 @@ struct Engine::Impl
     penX += -glyph.xBearing;
 
     // Traverses the characters of the right to left paragraph.
+    if(layout.isSplitToTwoHalves && !extendedToSecondHalf)
+    {
+      for(; characterLogicalIndex < bidiLine.characterRunForSecondHalfLine.numberOfCharacters;
+          ++characterLogicalIndex)
+      {
+        // Convert the character in the logical order into the character in the visual order.
+        const CharacterIndex characterVisualIndex = bidiLine.characterRunForSecondHalfLine.characterIndex + *(bidiLine.visualToLogicalMapSecondHalf + characterLogicalIndex);
+
+        // Get the number of glyphs of the character.
+        const Length numberOfGlyphs = *(glyphsPerCharacterBuffer + characterVisualIndex);
+
+        for(GlyphIndex index = 0u; index < numberOfGlyphs; ++index)
+        {
+          // Convert the character in the visual order into the glyph in the visual order.
+          const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex) + index;
+
+          DALI_ASSERT_DEBUG(glyphIndex < layoutParameters.textModel->mVisualModel->mGlyphs.Count());
+
+          const GlyphInfo& glyph    = *(glyphsBuffer + glyphIndex);
+          Vector2&         position = *(glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex);
+
+          position.x = penX + glyph.xBearing;
+          position.y = -glyph.yBearing;
+
+          penX += (glyph.advance + layoutParameters.interGlyphExtraAdvance);
+        }
+      }
+    }
+
+    characterLogicalIndex = extendedToSecondHalf ? characterLogicalIndex : 0u;
     for(; characterLogicalIndex < bidiLine.characterRun.numberOfCharacters;
         ++characterLogicalIndex)
     {
@@ -825,22 +1196,25 @@ struct Engine::Impl
    * @param[in] penY The vertical layout position.
    * @param[in] currentParagraphDirection The current paragraph's direction.
    * @param[in,out] isAutoScrollEnabled If the isAutoScrollEnabled is true and the height of the text exceeds the boundaries of the control the text is elided and the isAutoScrollEnabled is set to false to disable the autoscroll
+   * @param[in] ellipsisPosition Where is the location the text elide
    *
    * return Whether the line is ellipsized.
    */
-  bool EllipsisLine(const Parameters&     layoutParameters,
-                    LayoutBidiParameters& layoutBidiParameters,
-                    const LineLayout&     layout,
-                    Size&                 layoutSize,
-                    LineRun*              linesBuffer,
-                    Vector2*              glyphPositionsBuffer,
-                    Length&               numberOfLines,
-                    float                 penY,
-                    bool&                 isAutoScrollEnabled)
+  bool EllipsisLine(const Parameters&                 layoutParameters,
+                    LayoutBidiParameters&             layoutBidiParameters,
+                    const LineLayout&                 layout,
+                    Size&                             layoutSize,
+                    LineRun*                          linesBuffer,
+                    Vector2*                          glyphPositionsBuffer,
+                    Length&                           numberOfLines,
+                    float                             penY,
+                    bool&                             isAutoScrollEnabled,
+                    DevelText::EllipsisPosition::Type ellipsisPosition,
+                    bool                              enforceEllipsisInSingleLine)
   {
-    const bool ellipsis = isAutoScrollEnabled ? (penY - layout.descender > layoutParameters.boundingBox.height) : ((penY - layout.descender > layoutParameters.boundingBox.height) || ((mLayout == SINGLE_LINE_BOX) && (layout.length > layoutParameters.boundingBox.width)));
-
-    if(ellipsis)
+    const bool ellipsis    = enforceEllipsisInSingleLine || (isAutoScrollEnabled ? (penY - layout.descender > layoutParameters.boundingBox.height) : ((penY - layout.descender > layoutParameters.boundingBox.height) || ((mLayout == SINGLE_LINE_BOX) && (layout.length > layoutParameters.boundingBox.width))));
+    const bool isMultiline = !enforceEllipsisInSingleLine && (mLayout == MULTI_LINE_BOX);
+    if(ellipsis && (ellipsisPosition == DevelText::EllipsisPosition::END || !isMultiline))
     {
       isAutoScrollEnabled = false;
       // Do not layout more lines if ellipsis is enabled.
@@ -854,7 +1228,6 @@ struct Engine::Impl
       {
         // Get the last line and layout it again with the 'completelyFill' flag to true.
         lineRun = linesBuffer + (numberOfLines - 1u);
-
         penY -= layout.ascender - lineRun->descender + lineRun->lineSpacing;
 
         ellipsisLayout.glyphIndex = lineRun->glyphRun.glyphIndex;
@@ -866,6 +1239,7 @@ struct Engine::Impl
 
         lineRun->glyphRun.glyphIndex = 0u;
         ellipsisLayout.glyphIndex    = 0u;
+        lineRun->isSplitToTwoHalves  = false;
 
         ++numberOfLines;
       }
@@ -873,8 +1247,16 @@ struct Engine::Impl
       GetLineLayoutForBox(layoutParameters,
                           layoutBidiParameters,
                           ellipsisLayout,
+                          true,
+                          ellipsisPosition,
+                          enforceEllipsisInSingleLine,
                           true);
 
+      if(ellipsisPosition == DevelText::EllipsisPosition::START && !isMultiline)
+      {
+        lineRun->glyphRun.glyphIndex = ellipsisLayout.glyphIndex;
+      }
+
       lineRun->glyphRun.numberOfGlyphs         = ellipsisLayout.numberOfGlyphs;
       lineRun->characterRun.characterIndex     = ellipsisLayout.characterIndex;
       lineRun->characterRun.numberOfCharacters = ellipsisLayout.numberOfCharacters;
@@ -884,15 +1266,18 @@ struct Engine::Impl
       lineRun->descender                       = ellipsisLayout.descender;
       lineRun->ellipsis                        = true;
 
+      lineRun->isSplitToTwoHalves                               = ellipsisLayout.isSplitToTwoHalves;
+      lineRun->glyphRunSecondHalf.glyphIndex                    = ellipsisLayout.glyphIndexInSecondHalfLine;
+      lineRun->glyphRunSecondHalf.numberOfGlyphs                = ellipsisLayout.numberOfGlyphsInSecondHalfLine;
+      lineRun->characterRunForSecondHalfLine.characterIndex     = ellipsisLayout.characterIndexInSecondHalfLine;
+      lineRun->characterRunForSecondHalfLine.numberOfCharacters = ellipsisLayout.numberOfCharactersInSecondHalfLine;
+
       layoutSize.width = layoutParameters.boundingBox.width;
       if(layoutSize.height < Math::MACHINE_EPSILON_1000)
       {
         layoutSize.height += (lineRun->ascender + -lineRun->descender) + lineRun->lineSpacing;
       }
 
-      const GlyphInfo* const glyphsBuffer = layoutParameters.textModel->mVisualModel->mGlyphs.Begin();
-      const float            outlineWidth = static_cast<float>(layoutParameters.textModel->GetOutlineWidth());
-
       const Vector<BidirectionalLineInfoRun>& bidirectionalLinesInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo;
 
       if(layoutBidiParameters.isBidirectional)
@@ -904,8 +1289,14 @@ struct Engine::Impl
             ++it, ++layoutBidiParameters.bidiLineIndex)
         {
           const BidirectionalLineInfoRun& run = *it;
-
-          if(ellipsisLayout.characterIndex == run.characterRun.characterIndex)
+          //To handle case when the laid characters exist in next line.
+          //More than one BidirectionalLineInfoRun could start with same character.
+          //When need to check also numberOfCharacters in line.
+          //Note: This fixed the incorrect view of extra spaces of RTL as in Arabic then view ellipsis glyph
+          if(ellipsisLayout.characterIndex == run.characterRun.characterIndex &&
+             ellipsisLayout.numberOfCharacters == run.characterRun.numberOfCharacters &&
+             ellipsisLayout.characterIndexInSecondHalfLine == run.characterRunForSecondHalfLine.characterIndex &&
+             ellipsisLayout.numberOfCharactersInSecondHalfLine == run.characterRunForSecondHalfLine.numberOfCharacters)
           {
             // Found where to insert the bidi line info.
             break;
@@ -928,11 +1319,9 @@ struct Engine::Impl
       else
       {
         lineRun->direction = LTR;
-        SetGlyphPositions(glyphsBuffer + lineRun->glyphRun.glyphIndex,
-                          ellipsisLayout.numberOfGlyphs,
-                          outlineWidth,
-                          layoutParameters.interGlyphExtraAdvance,
-                          glyphPositionsBuffer + lineRun->glyphRun.glyphIndex - layoutParameters.startGlyphIndex);
+        SetGlyphPositions(layoutParameters,
+                          glyphPositionsBuffer,
+                          ellipsisLayout);
       }
     }
 
@@ -968,6 +1357,12 @@ struct Engine::Impl
     lineRun.width                           = layout.length;
     lineRun.extraLength                     = std::ceil(layout.whiteSpaceLengthEndOfLine);
 
+    lineRun.isSplitToTwoHalves                               = layout.isSplitToTwoHalves;
+    lineRun.glyphRunSecondHalf.glyphIndex                    = layout.glyphIndexInSecondHalfLine;
+    lineRun.glyphRunSecondHalf.numberOfGlyphs                = layout.numberOfGlyphsInSecondHalfLine;
+    lineRun.characterRunForSecondHalfLine.characterIndex     = layout.characterIndexInSecondHalfLine;
+    lineRun.characterRunForSecondHalfLine.numberOfCharacters = layout.numberOfCharactersInSecondHalfLine;
+
     // Rounds upward to avoid a non integer size.
     lineRun.width = std::ceil(lineRun.width);
 
@@ -1095,10 +1490,11 @@ struct Engine::Impl
     }
   }
 
-  bool LayoutText(Parameters& layoutParameters,
-                  Size&       layoutSize,
-                  bool        elideTextEnabled,
-                  bool&       isAutoScrollEnabled)
+  bool LayoutText(Parameters&                       layoutParameters,
+                  Size&                             layoutSize,
+                  bool                              elideTextEnabled,
+                  bool&                             isAutoScrollEnabled,
+                  DevelText::EllipsisPosition::Type ellipsisPosition)
   {
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->LayoutText\n");
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  box size %f, %f\n", layoutParameters.boundingBox.width, layoutParameters.boundingBox.height);
@@ -1106,6 +1502,12 @@ struct Engine::Impl
     layoutParameters.textModel->mVisualModel->mHyphen.glyph.Clear();
     layoutParameters.textModel->mVisualModel->mHyphen.index.Clear();
 
+    //Reset indices of ElidedGlyphs
+    layoutParameters.textModel->mVisualModel->SetStartIndexOfElidedGlyphs(0u);
+    layoutParameters.textModel->mVisualModel->SetEndIndexOfElidedGlyphs(layoutParameters.textModel->GetNumberOfGlyphs() - 1u);
+    layoutParameters.textModel->mVisualModel->SetFirstMiddleIndexOfElidedGlyphs(0u);
+    layoutParameters.textModel->mVisualModel->SetSecondMiddleIndexOfElidedGlyphs(0u);
+
     Vector<LineRun>& lines = layoutParameters.textModel->mVisualModel->mLines;
 
     if(0u == layoutParameters.numberOfGlyphs)
@@ -1202,8 +1604,9 @@ struct Engine::Impl
       linesBuffer = lines.Begin();
     }
 
-    float penY = CalculateLineOffset(lines,
+    float penY            = CalculateLineOffset(lines,
                                      layoutParameters.startLineIndex);
+    bool  anyLineIsEliped = false;
     for(GlyphIndex index = layoutParameters.startGlyphIndex; index < lastGlyphPlusOne;)
     {
       layoutBidiParameters.Clear();
@@ -1272,7 +1675,10 @@ struct Engine::Impl
       GetLineLayoutForBox(layoutParameters,
                           layoutBidiParameters,
                           layout,
-                          false);
+                          false,
+                          ellipsisPosition,
+                          false,
+                          elideTextEnabled);
 
       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "           glyph index %d\n", layout.glyphIndex);
       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "       character index %d\n", layout.characterIndex);
@@ -1280,7 +1686,7 @@ struct Engine::Impl
       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  number of characters %d\n", layout.numberOfCharacters);
       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "                length %f\n", layout.length);
 
-      if(0u == layout.numberOfGlyphs)
+      if(0u == layout.numberOfGlyphs + layout.numberOfGlyphsInSecondHalfLine)
       {
         // The width is too small and no characters are laid-out.
         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--LayoutText width too small!\n\n");
@@ -1313,11 +1719,29 @@ struct Engine::Impl
                                 glyphPositionsBuffer,
                                 numberOfLines,
                                 penY,
-                                isAutoScrollEnabled);
+                                isAutoScrollEnabled,
+                                ellipsisPosition,
+                                false);
       }
 
-      if(ellipsis)
+      if(ellipsis && ((ellipsisPosition == DevelText::EllipsisPosition::END) || (numberOfLines == 1u)))
       {
+        const bool isMultiline = mLayout == MULTI_LINE_BOX;
+        if(isMultiline && ellipsisPosition != DevelText::EllipsisPosition::END)
+        {
+          ellipsis = EllipsisLine(layoutParameters,
+                                  layoutBidiParameters,
+                                  layout,
+                                  layoutSize,
+                                  linesBuffer,
+                                  glyphPositionsBuffer,
+                                  numberOfLines,
+                                  penY,
+                                  isAutoScrollEnabled,
+                                  ellipsisPosition,
+                                  true);
+        }
+
         //clear hyphen from ellipsis line
         const Length* hyphenIndices = layoutParameters.textModel->mVisualModel->mHyphen.index.Begin();
         Length        hyphensCount  = layoutParameters.textModel->mVisualModel->mHyphen.glyph.Size();
@@ -1334,8 +1758,11 @@ struct Engine::Impl
       }
       else
       {
+        //In START location of ellipsis whether to shift lines or not.
+        anyLineIsEliped |= ellipsis;
+
         // Whether the last line has been laid-out.
-        const bool isLastLine = index + layout.numberOfGlyphs == totalNumberOfGlyphs;
+        const bool isLastLine = index + (layout.numberOfGlyphs + layout.numberOfGlyphsInSecondHalfLine) == totalNumberOfGlyphs;
 
         if(numberOfLines == linesCapacity)
         {
@@ -1355,7 +1782,7 @@ struct Engine::Impl
                          numberOfLines,
                          isLastLine);
 
-        const GlyphIndex nextIndex = index + layout.numberOfGlyphs;
+        const GlyphIndex nextIndex = index + layout.numberOfGlyphs + layout.numberOfGlyphsInSecondHalfLine;
 
         if((nextIndex == totalNumberOfGlyphs) &&
            layoutParameters.isLastNewParagraph &&
@@ -1375,16 +1802,13 @@ struct Engine::Impl
           }
 
           UpdateTextLayout(layoutParameters,
-                           layout.characterIndex + layout.numberOfCharacters,
-                           index + layout.numberOfGlyphs,
+                           layout.characterIndex + (layout.numberOfCharacters + layout.numberOfCharactersInSecondHalfLine),
+                           index + (layout.numberOfGlyphs + layout.numberOfGlyphsInSecondHalfLine),
                            layoutSize,
                            linesBuffer,
                            numberOfLines);
         } // whether to add a last line.
 
-        const GlyphInfo* const glyphsBuffer = layoutParameters.textModel->mVisualModel->mGlyphs.Begin();
-        const float            outlineWidth = static_cast<float>(layoutParameters.textModel->GetOutlineWidth());
-
         const BidirectionalLineInfoRun* const bidirectionalLineInfo = (layoutBidiParameters.isBidirectional && !bidirectionalLinesInfo.Empty()) ? &bidirectionalLinesInfo[layoutBidiParameters.bidiLineIndex] : nullptr;
 
         if((nullptr != bidirectionalLineInfo) &&
@@ -1399,11 +1823,9 @@ struct Engine::Impl
         else
         {
           // Sets the positions of the glyphs.
-          SetGlyphPositions(glyphsBuffer + index,
-                            layout.numberOfGlyphs,
-                            outlineWidth,
-                            layoutParameters.interGlyphExtraAdvance,
-                            glyphPositionsBuffer + index - layoutParameters.startGlyphIndex);
+          SetGlyphPositions(layoutParameters,
+                            glyphPositionsBuffer,
+                            layout);
         }
 
         // Updates the vertical pen's position.
@@ -1421,6 +1843,52 @@ struct Engine::Impl
       } // no ellipsis
     }   // end for() traversing glyphs.
 
+    //Shift lines to up if ellipsis and multilines and set ellipsis of first line to true
+    if(anyLineIsEliped && numberOfLines > 1u)
+    {
+      if(ellipsisPosition == DevelText::EllipsisPosition::START)
+      {
+        Length lineIndex = 0;
+        while(lineIndex < numberOfLines && layoutParameters.boundingBox.height < layoutSize.height)
+        {
+          LineRun& delLine = linesBuffer[lineIndex];
+          delLine.ellipsis = true;
+
+          layoutSize.height -= (delLine.ascender + -delLine.descender) + delLine.lineSpacing;
+          for(Length lineIndex = 0; lineIndex < numberOfLines - 1; lineIndex++)
+          {
+            linesBuffer[lineIndex]          = linesBuffer[lineIndex + 1];
+            linesBuffer[lineIndex].ellipsis = false;
+          }
+          numberOfLines--;
+          lineIndex++;
+        }
+        linesBuffer[0u].ellipsis = true;
+      }
+      else if(ellipsisPosition == DevelText::EllipsisPosition::MIDDLE)
+      {
+        Length middleLineIndex   = (numberOfLines) / 2u;
+        Length ellipsisLineIndex = 0u;
+        while(1u < numberOfLines && 0u < middleLineIndex && layoutParameters.boundingBox.height < layoutSize.height)
+        {
+          LineRun& delLine = linesBuffer[middleLineIndex];
+          delLine.ellipsis = true;
+
+          layoutSize.height -= (delLine.ascender + -delLine.descender) + delLine.lineSpacing;
+          for(Length lineIndex = middleLineIndex; lineIndex < numberOfLines - 1; lineIndex++)
+          {
+            linesBuffer[lineIndex]          = linesBuffer[lineIndex + 1];
+            linesBuffer[lineIndex].ellipsis = false;
+          }
+          numberOfLines--;
+          ellipsisLineIndex = middleLineIndex > 0u ? middleLineIndex - 1u : 0u;
+          middleLineIndex   = (numberOfLines) / 2u;
+        }
+
+        linesBuffer[ellipsisLineIndex].ellipsis = true;
+      }
+    }
+
     if(updateCurrentBuffer)
     {
       glyphPositions.Insert(glyphPositions.Begin() + layoutParameters.startGlyphIndex,
@@ -1662,15 +2130,17 @@ int Engine::GetCursorWidth() const
   return static_cast<int>(mImpl->mCursorWidth);
 }
 
-bool Engine::LayoutText(Parameters& layoutParameters,
-                        Size&       layoutSize,
-                        bool        elideTextEnabled,
-                        bool&       isAutoScrollEnabled)
+bool Engine::LayoutText(Parameters&                       layoutParameters,
+                        Size&                             layoutSize,
+                        bool                              elideTextEnabled,
+                        bool&                             isAutoScrollEnabled,
+                        DevelText::EllipsisPosition::Type ellipsisPosition)
 {
   return mImpl->LayoutText(layoutParameters,
                            layoutSize,
                            elideTextEnabled,
-                           isAutoScrollEnabled);
+                           isAutoScrollEnabled,
+                           ellipsisPosition);
 }
 
 void Engine::Align(const Size&                     size,
index 46cc972..e11c549 100644 (file)
@@ -28,6 +28,9 @@
 #include <dali-toolkit/internal/text/metrics.h>
 #include <dali-toolkit/public-api/text/text-enumerations.h>
 
+//DEVEL INCLUDE
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+
 namespace Dali
 {
 namespace Toolkit
@@ -104,13 +107,15 @@ public:
    * @param[out] layoutSize The size of the text after it has been laid-out.
    * @param[in] elideTextEnabled Whether the text elide is enabled.
    * @param[in,out] isAutoScrollEnabled If the isAutoScrollEnabled is true and the height of the text exceeds the boundaries of the control the text is elided and the isAutoScrollEnabled is set to false to disable the autoscroll
+   * @param[in] ellipsisPosition The location of the text ellipsis
    *
    * @return \e true if the text has been re-laid-out. \e false means the given width is too small to layout even a single character.
    */
-  bool LayoutText(Parameters& layoutParameters,
-                  Size&       layoutSize,
-                  bool        elideTextEnabled,
-                  bool&       isAutoScrollEnabled);
+  bool LayoutText(Parameters&                       layoutParameters,
+                  Size&                             layoutSize,
+                  bool                              elideTextEnabled,
+                  bool&                             isAutoScrollEnabled,
+                  DevelText::EllipsisPosition::Type ellipsisPosition);
 
   /**
    * @brief Aligns the laid out lines.
index f4d13e0..ff826e6 100644 (file)
@@ -33,16 +33,19 @@ namespace Text
  */
 struct LineRun
 {
-  GlyphRun           glyphRun;        ///< The initial glyph index and the number of glyphs of the run.
-  CharacterRun       characterRun;    ///< The initial character index and the number of characters of the run.
-  float              width;           ///< The line's width.
-  float              ascender;        ///< The line's ascender.
-  float              descender;       ///< The line's descender.
-  float              extraLength;     ///< The length of the white spaces at the end of the line.
-  float              alignmentOffset; ///< The horizontal alignment offset.
-  float              lineSpacing;     ///< The line's spacing
-  CharacterDirection direction : 1;   ///< Direction of the first character of the paragraph.
-  bool               ellipsis : 1;    ///< Wheter ellipsis is added to the line.
+  GlyphRun           glyphRun;                      ///< The initial glyph index and the number of glyphs of the run.
+  CharacterRun       characterRun;                  ///< The initial character index and the number of characters of the run.
+  float              width;                         ///< The line's width.
+  float              ascender;                      ///< The line's ascender.
+  float              descender;                     ///< The line's descender.
+  float              extraLength;                   ///< The length of the white spaces at the end of the line.
+  float              alignmentOffset;               ///< The horizontal alignment offset.
+  float              lineSpacing;                   ///< The line's spacing
+  CharacterDirection direction : 1;                 ///< Direction of the first character of the paragraph.
+  bool               ellipsis : 1;                  ///< Wheter ellipsis is added to the line.
+  bool               isSplitToTwoHalves;            ///< Whether the second half is defined. When split line to two halves to set Ellipsis in the MIDDLE of line. The second half is the second part of line after Ellipsis.
+  GlyphRun           glyphRunSecondHalf;            ///< The initial glyph index and the number of glyphs of the run for the second half of line.
+  CharacterRun       characterRunForSecondHalfLine; ///< The initial character index and the number of characters of the run for the second half of line.
 };
 
 } // namespace Text
index 1023dc4..ef80844 100644 (file)
@@ -46,7 +46,7 @@ Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT
 const float    ZERO(0.0f);
 const float    HALF(0.5f);
 const float    ONE(1.0f);
-const uint32_t DOUBLE_PIXEL_PADDING = 4u;//Padding will be added twice to Atlas
+const uint32_t DOUBLE_PIXEL_PADDING = 4u; //Padding will be added twice to Atlas
 const uint16_t NO_OUTLINE           = 0u;
 } // namespace
 
@@ -249,13 +249,12 @@ struct AtlasRenderer::Impl
           // If CheckAtlas in AtlasManager::Add can't fit the bitmap in the current atlas it will create a new atlas
 
           // Setting the block size and size of new atlas does not mean a new one will be created. An existing atlas may still surffice.
-          uint32_t default_width = defaultTextAtlasSize.width;
+          uint32_t default_width  = defaultTextAtlasSize.width;
           uint32_t default_height = defaultTextAtlasSize.height;
 
-          while (
+          while(
             (blockSize.mNeededBlockWidth >= (default_width - (DOUBLE_PIXEL_PADDING + 1u)) ||
-             blockSize.mNeededBlockHeight >= (default_height - (DOUBLE_PIXEL_PADDING + 1u)))
-            &&
+             blockSize.mNeededBlockHeight >= (default_height - (DOUBLE_PIXEL_PADDING + 1u))) &&
             (default_width < maximumTextAtlasSize.width &&
              default_height < maximumTextAtlasSize.height))
           {
@@ -433,6 +432,11 @@ struct AtlasRenderer::Impl
     const Length*    hyphenIndices = view.GetHyphenIndices();
     const Length     hyphensCount  = view.GetHyphensCount();
 
+    // Elided text info. Indices according to elided text.
+    const auto startIndexOfGlyphs              = view.GetStartIndexOfElidedGlyphs();
+    const auto firstMiddleIndexOfElidedGlyphs  = view.GetFirstMiddleIndexOfElidedGlyphs();
+    const auto secondMiddleIndexOfElidedGlyphs = view.GetSecondMiddleIndexOfElidedGlyphs();
+
     const bool useDefaultColor = (NULL == colorsBuffer);
 
     // Get the underline runs.
@@ -466,13 +470,23 @@ struct AtlasRenderer::Impl
     uint32_t               hyphenIndex = 0;
 
     //For septated underlined chunks. (this is for Markup case)
-    uint32_t underlineChunkId = 0u; // give id for each chunk.
-    bool     isPreUnderlined = false; // status of underlined for previous glyph.
+    uint32_t underlineChunkId = 0u;    // give id for each chunk.
+    bool     isPreUnderlined  = false; // status of underlined for previous glyph.
+
+    //Skip hyphenIndices less than startIndexOfGlyphs or between two middle of elided text
+    if(hyphenIndices)
+    {
+      while((hyphenIndex < hyphensCount) && (hyphenIndices[hyphenIndex] < startIndexOfGlyphs ||
+                                             (hyphenIndices[hyphenIndex] > firstMiddleIndexOfElidedGlyphs && hyphenIndices[hyphenIndex] < secondMiddleIndexOfElidedGlyphs)))
+      {
+        ++hyphenIndex;
+      }
+    }
 
     for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
     {
       GlyphInfo glyph;
-      bool      addHyphen = ((hyphenIndex < hyphensCount) && hyphenIndices && (i == hyphenIndices[hyphenIndex]));
+      bool      addHyphen = ((hyphenIndex < hyphensCount) && hyphenIndices && ((i + startIndexOfGlyphs) == hyphenIndices[hyphenIndex]));
       if(addHyphen && hyphens)
       {
         glyph = hyphens[hyphenIndex];
@@ -601,10 +615,9 @@ struct AtlasRenderer::Impl
                        0u);
         }
 
-
         //The new underlined chunk. Add new id if they are not consecutive indices (this is for Markup case)
         // Examples: "Hello <u>World</u> Hello <u>World</u>", "<u>World</u> Hello <u>World</u>", "<u>   World</u> Hello <u>World</u>"
-        if( isPreUnderlined && (isPreUnderlined != isGlyphUnderlined))
+        if(isPreUnderlined && (isPreUnderlined != isGlyphUnderlined))
         {
           underlineChunkId++;
         }
@@ -871,7 +884,7 @@ struct AtlasRenderer::Impl
       extent.mUnderlinePosition  = underlinePosition;
       extent.mUnderlineThickness = underlineThickness;
       extent.mMeshRecordIndex    = index;
-      extent.mUnderlineChunkId = underlineChunkId;
+      extent.mUnderlineChunkId   = underlineChunkId;
       extents.PushBack(extent);
     }
   }
index 6fadaed..cea2a19 100644 (file)
@@ -648,14 +648,16 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
   const unsigned int bufferSizeInt  = bufferWidth * bufferHeight;
   const unsigned int bufferSizeChar = 4u * bufferSizeInt;
 
-  Length numberOfGlyphs = mModel->GetNumberOfGlyphs();
+  //Elided text in ellipsis at START could start on index greater than 0
+  auto startIndexOfGlyphs = mModel->GetStartIndexOfElidedGlyphs();
+  auto endIndexOfGlyphs   = mModel->GetEndIndexOfElidedGlyphs();
 
   Devel::PixelBuffer imageBuffer;
 
   if(RENDER_MASK == behaviour)
   {
     // Generate the image buffer as an alpha mask for color glyphs.
-    imageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_MASK, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs - 1);
+    imageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_MASK, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
   }
   else if(RENDER_NO_TEXT == behaviour)
   {
@@ -666,7 +668,7 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
   else
   {
     // Generate the image buffer for the text with no style.
-    imageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_NONE, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs - 1);
+    imageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_NONE, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
   }
 
   if((RENDER_NO_STYLES != behaviour) && (RENDER_MASK != behaviour))
@@ -676,7 +678,7 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
     if(outlineWidth != 0u)
     {
       // Create the image buffer for outline
-      Devel::PixelBuffer outlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_OUTLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs - 1);
+      Devel::PixelBuffer outlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_OUTLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
 
       // Combine the two buffers
       imageBuffer = CombineImageBuffer(imageBuffer, outlineImageBuffer, bufferWidth, bufferHeight);
@@ -689,7 +691,7 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
     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, penX, penY, 0u, numberOfGlyphs - 1);
+      Devel::PixelBuffer shadowImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_SHADOW, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
 
       // Check whether it will be a soft shadow
       const float& blurRadius = mModel->GetShadowBlurRadius();
@@ -708,7 +710,7 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
     if(underlineEnabled)
     {
       // Create the image buffer for underline
-      Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs - 1);
+      Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
 
       // Combine the two buffers
       imageBuffer = CombineImageBuffer(imageBuffer, underlineImageBuffer, bufferWidth, bufferHeight);
@@ -723,7 +725,7 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
 
       if(backgroundEnabled)
       {
-        backgroundImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_BACKGROUND, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs - 1);
+        backgroundImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_BACKGROUND, ignoreHorizontalAlignment, pixelFormat, penX, penY, startIndexOfGlyphs, endIndexOfGlyphs);
       }
       else
       {
@@ -755,7 +757,6 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
   // Retrieve lines, glyphs, positions and colors from the view model.
   const Length            modelNumberOfLines = mModel->GetNumberOfLines();
   const LineRun* const    modelLinesBuffer   = mModel->GetLines();
-  const Length            numberOfGlyphs     = mModel->GetNumberOfGlyphs();
   const GlyphInfo* const  glyphsBuffer       = mModel->GetGlyphs();
   const Vector2* const    positionBuffer     = mModel->GetLayout();
   const Vector4* const    colorsBuffer       = mModel->GetColors();
@@ -764,6 +765,13 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
   const Length*           hyphenIndices      = mModel->GetHyphenIndices();
   const Length            hyphensCount       = mModel->GetHyphensCount();
 
+  // Elided text info. Indices according to elided text and Ellipsis position.
+  const auto startIndexOfGlyphs              = mModel->GetStartIndexOfElidedGlyphs();
+  const auto endIndexOfGlyphs                = mModel->GetEndIndexOfElidedGlyphs();
+  const auto firstMiddleIndexOfElidedGlyphs  = mModel->GetFirstMiddleIndexOfElidedGlyphs();
+  const auto secondMiddleIndexOfElidedGlyphs = mModel->GetSecondMiddleIndexOfElidedGlyphs();
+  const auto ellipsisPosition                = mModel->GetEllipsisPosition();
+
   // Whether to use the default color.
   const bool     useDefaultColor = (NULL == colorsBuffer);
   const Vector4& defaultColor    = mModel->GetDefaultColor();
@@ -846,8 +854,11 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
     bool  addHyphen       = false;
 
     // Traverses the glyphs of the line.
-    const GlyphIndex endGlyphIndex = std::min(numberOfGlyphs, line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs);
-    for(GlyphIndex glyphIndex = line.glyphRun.glyphIndex; glyphIndex < endGlyphIndex; ++glyphIndex)
+    const GlyphIndex startGlyphIndex = std::max(line.glyphRun.glyphIndex, startIndexOfGlyphs);
+    GlyphIndex       endGlyphIndex   = (line.isSplitToTwoHalves ? line.glyphRunSecondHalf.glyphIndex + line.glyphRunSecondHalf.numberOfGlyphs : line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs) - 1u;
+    endGlyphIndex                    = std::min(endGlyphIndex, endIndexOfGlyphs);
+
+    for(GlyphIndex glyphIndex = startGlyphIndex; glyphIndex <= endGlyphIndex; ++glyphIndex)
     {
       if(glyphIndex < fromGlyphIndex || glyphIndex > toGlyphIndex)
       {
@@ -855,6 +866,25 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
         continue;
       }
 
+      //To handle START case of ellipsis, the first glyph has been shifted
+      //glyphIndex represent indices in whole glyphs but elidedGlyphIndex represents indices in elided Glyphs
+      GlyphIndex elidedGlyphIndex = glyphIndex - startIndexOfGlyphs;
+
+      //To handle MIDDLE case of ellipsis, the first glyph in the second half of line has been shifted and skip the removed glyph from middle.
+      if(ellipsisPosition == DevelText::EllipsisPosition::MIDDLE)
+      {
+        if(glyphIndex > firstMiddleIndexOfElidedGlyphs &&
+           glyphIndex < secondMiddleIndexOfElidedGlyphs)
+        {
+          // Ignore any glyph that removed for MIDDLE ellipsis
+          continue;
+        }
+        if(glyphIndex >= secondMiddleIndexOfElidedGlyphs)
+        {
+          elidedGlyphIndex -= (secondMiddleIndexOfElidedGlyphs - firstMiddleIndexOfElidedGlyphs - 1u);
+        }
+      }
+
       // Retrieve the glyph's info.
       const GlyphInfo* glyphInfo;
 
@@ -865,7 +895,7 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
       }
       else
       {
-        glyphInfo = glyphsBuffer + glyphIndex;
+        glyphInfo = glyphsBuffer + elidedGlyphIndex;
       }
 
       if((glyphInfo->width < Math::MACHINE_EPSILON_1000) ||
@@ -886,11 +916,11 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
       } // underline
 
       // Retrieves the glyph's position.
-      Vector2 position = *(positionBuffer + glyphIndex);
+      Vector2 position = *(positionBuffer + elidedGlyphIndex);
 
       if(addHyphen)
       {
-        GlyphInfo tempInfo = *(glyphsBuffer + glyphIndex);
+        GlyphInfo tempInfo = *(glyphsBuffer + elidedGlyphIndex);
         position.x         = position.x + tempInfo.advance - tempInfo.xBearing + glyphInfo->xBearing;
         position.y         = -glyphInfo->yBearing;
       }
index 4ad0b14..35c0a87 100644 (file)
@@ -35,7 +35,11 @@ ViewModel::ViewModel(const ModelInterface* const model)
 : mModel(model),
   mElidedGlyphs(),
   mElidedLayout(),
-  mIsTextElided(false)
+  mIsTextElided(false),
+  mStartIndexOfElidedGlyphs(0u),
+  mEndIndexOfElidedGlyphs(0u),
+  mFirstMiddleIndexOfElidedGlyphs(0u),
+  mSecondMiddleIndexOfElidedGlyphs(0u)
 {
 }
 
@@ -73,6 +77,11 @@ DevelText::VerticalLineAlignment::Type ViewModel::GetVerticalLineAlignment() con
   return mModel->GetVerticalLineAlignment();
 }
 
+DevelText::EllipsisPosition::Type ViewModel::GetEllipsisPosition() const
+{
+  return mModel->GetEllipsisPosition();
+}
+
 bool ViewModel::IsTextElideEnabled() const
 {
   return mModel->IsTextElideEnabled();
@@ -112,6 +121,46 @@ Length ViewModel::GetNumberOfGlyphs() const
   return 0u;
 }
 
+GlyphIndex ViewModel::GetStartIndexOfElidedGlyphs() const
+{
+  if(mIsTextElided && mModel->IsTextElideEnabled())
+  {
+    return mStartIndexOfElidedGlyphs;
+  }
+
+  return mModel->GetStartIndexOfElidedGlyphs();
+}
+
+GlyphIndex ViewModel::GetEndIndexOfElidedGlyphs() const
+{
+  if(mIsTextElided && mModel->IsTextElideEnabled())
+  {
+    return mEndIndexOfElidedGlyphs;
+  }
+
+  return mModel->GetEndIndexOfElidedGlyphs();
+}
+
+GlyphIndex ViewModel::GetFirstMiddleIndexOfElidedGlyphs() const
+{
+  if(mIsTextElided && mModel->IsTextElideEnabled())
+  {
+    return mFirstMiddleIndexOfElidedGlyphs;
+  }
+
+  return mModel->GetFirstMiddleIndexOfElidedGlyphs();
+}
+
+GlyphIndex ViewModel::GetSecondMiddleIndexOfElidedGlyphs() const
+{
+  if(mIsTextElided && mModel->IsTextElideEnabled())
+  {
+    return mSecondMiddleIndexOfElidedGlyphs;
+  }
+
+  return mModel->GetSecondMiddleIndexOfElidedGlyphs();
+}
+
 const GlyphInfo* const ViewModel::GetGlyphs() const
 {
   if(mIsTextElided && mModel->IsTextElideEnabled())
@@ -252,157 +301,283 @@ Length ViewModel::GetHyphensCount() const
 
 void ViewModel::ElideGlyphs()
 {
-  mIsTextElided = false;
+  mIsTextElided             = false;
+  mStartIndexOfElidedGlyphs = mFirstMiddleIndexOfElidedGlyphs = mSecondMiddleIndexOfElidedGlyphs = 0;
+  mEndIndexOfElidedGlyphs                                                                        = mModel->GetNumberOfGlyphs() - 1u;
+
+  auto ellipsisPosition = GetEllipsisPosition();
 
-  if(mModel->IsTextElideEnabled())
+  if(IsTextElideEnabled())
   {
     const Length numberOfLines = mModel->GetNumberOfLines();
     if(0u != numberOfLines)
     {
       const LineRun* const lines = mModel->GetLines();
 
-      const LineRun& lastLine              = *(lines + (numberOfLines - 1u));
-      const Length   numberOfLaidOutGlyphs = lastLine.glyphRun.glyphIndex + lastLine.glyphRun.numberOfGlyphs;
+      //Get line of ellipsis
+      const LineRun* ellipsisLine     = nullptr;
+      const LineRun* ellipsisNextLine = nullptr;
 
-      if(lastLine.ellipsis && (0u != numberOfLaidOutGlyphs))
+      for(Length lineIndex = 0; lineIndex < numberOfLines; lineIndex++)
       {
-        mIsTextElided                          = true;
-        TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+        const LineRun* line = (lines + lineIndex);
+        if(line->ellipsis)
+        {
+          ellipsisLine = line;
+          if(lineIndex < numberOfLines - 1u)
+          {
+            ellipsisNextLine = (lines + lineIndex + 1u);
+          }
+          break;
+        }
+      }
 
-        const GlyphInfo* const glyphs    = mModel->GetGlyphs();
-        const Vector2* const   positions = mModel->GetLayout();
+      // Check if there is a line contains Ellipsis.
+      // Then find total number of glyphs and total number of laid out glyphs.
+      // Check where to set Ellipsis glyph in line.
+      // Determine index of Ellipsis glyph and how many glyphs should be replaced by Ellipsis glyph, according to width of Ellipsis glyph.
+      if(ellipsisLine != nullptr)
+      {
+        // Total number of glyphs.
+        const Length numberOfGlyphs = mModel->GetNumberOfGlyphs();
+        // Total number of laid out glyphs.
+        Length numberOfActualLaidOutGlyphs = 0u;
 
-        // Copy the glyphs to be elided.
-        mElidedGlyphs.Resize(numberOfLaidOutGlyphs);
-        mElidedLayout.Resize(numberOfLaidOutGlyphs);
+        // Accumulate laid out glyphs for each line to find total number of laid out glyphs.
+        for(Length lineIndex = 0u; lineIndex < numberOfLines; lineIndex++)
+        {
+          numberOfActualLaidOutGlyphs += lines[lineIndex].glyphRun.numberOfGlyphs + lines[lineIndex].glyphRunSecondHalf.numberOfGlyphs;
+        }
 
-        GlyphInfo* elidedGlyphsBuffer    = mElidedGlyphs.Begin();
-        Vector2*   elidedPositionsBuffer = mElidedLayout.Begin();
+        // Make sure there are laid out glyphs.
+        if(0u != numberOfActualLaidOutGlyphs)
+        {
+          // There are elided glyphs.
+          mIsTextElided                          = true;
+          TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
 
-        memcpy(elidedGlyphsBuffer, glyphs, numberOfLaidOutGlyphs * sizeof(GlyphInfo));
-        memcpy(elidedPositionsBuffer, positions, numberOfLaidOutGlyphs * sizeof(Vector2));
+          // Retrieve the whole glyphs and their positions.
+          const GlyphInfo* const glyphs    = mModel->GetGlyphs();
+          const Vector2* const   positions = mModel->GetLayout();
 
-        const Size& controlSize = mModel->GetControlSize();
+          // Copy the glyphs to be elided.
+          mElidedGlyphs.Resize(numberOfGlyphs);
+          mElidedLayout.Resize(numberOfGlyphs);
+          GlyphInfo* elidedGlyphsBuffer    = mElidedGlyphs.Begin();
+          Vector2*   elidedPositionsBuffer = mElidedLayout.Begin();
 
-        if((1u == numberOfLines) &&
-           (lastLine.ascender - lastLine.descender > controlSize.height))
-        {
-          // Get the first glyph which is going to be replaced and the ellipsis glyph.
-          GlyphInfo&       glyphToRemove = *elidedGlyphsBuffer;
-          const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph(fontClient.GetPointSize(glyphToRemove.fontId));
+          memcpy(elidedGlyphsBuffer, glyphs, numberOfGlyphs * sizeof(GlyphInfo));
+          memcpy(elidedPositionsBuffer, positions, numberOfGlyphs * sizeof(Vector2));
 
-          // Change the 'x' and 'y' position of the ellipsis glyph.
-          Vector2& position = *elidedPositionsBuffer;
+          const Size& controlSize = mModel->GetControlSize();
 
-          position.x = ellipsisGlyph.xBearing;
-          position.y = -lastLine.ascender + controlSize.height - ellipsisGlyph.yBearing;
+          // Set index where to set Ellipsis according to the selected position of Ellipsis.
+          // Start with this index to replace its glyph by Ellipsis, if the width  is not enough, then remove more glyphs.
+          GlyphIndex startIndexOfEllipsis = 0u;
+          if(ellipsisPosition == DevelText::EllipsisPosition::START)
+          {
+            // It's the fisrt glyph in line.
+            startIndexOfEllipsis = ellipsisLine->glyphRun.glyphIndex;
+          }
+          else if(ellipsisPosition == DevelText::EllipsisPosition::MIDDLE)
+          {
+            // It's the second middle of the line in case the line split to two halves.
+            // Otherwise it's It's the last glyph in line (line before all removed lines).
+            startIndexOfEllipsis = ellipsisLine->isSplitToTwoHalves ? (ellipsisLine->glyphRunSecondHalf.glyphIndex) : (ellipsisLine->glyphRun.glyphIndex + ellipsisLine->glyphRun.numberOfGlyphs - 1u);
+          }
+          else // DevelText::EllipsisPosition::END
+          {
+            // It's the last glyph in line.
+            startIndexOfEllipsis = ellipsisLine->glyphRun.glyphIndex + ellipsisLine->glyphRun.numberOfGlyphs - 1u;
+          }
 
-          // Replace the glyph by the ellipsis glyph and resize the buffers.
-          glyphToRemove = ellipsisGlyph;
+          // When the hight is not enough then show one glyph and that should be the first laid out glyph.
+          if((1u == numberOfLines) &&
+             (ellipsisLine->ascender - ellipsisLine->descender > controlSize.height))
+          {
+            // Replace the first glyph with ellipsis glyph
+            auto indexOfFirstGlyph = (ellipsisPosition == DevelText::EllipsisPosition::START) ? startIndexOfEllipsis : 0u;
 
-          mElidedGlyphs.Resize(1u);
-          mElidedLayout.Resize(1u);
+            // Regardless where the location of ellipsis,in-case the hight of line is greater than control's height
+            // then replace the first glyph with ellipsis glyph.
 
-          return;
-        }
+            // Get the first glyph which is going to be replaced and the ellipsis glyph.
+            GlyphInfo&       glyphToRemove = *(elidedGlyphsBuffer + indexOfFirstGlyph);
+            const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph(fontClient.GetPointSize(glyphToRemove.fontId));
 
-        // firstPenX, penY and firstPenSet are used to position the ellipsis glyph if needed.
-        float firstPenX   = 0.f; // Used if rtl text is elided.
-        float penY        = 0.f;
-        bool  firstPenSet = false;
+            // Change the 'x' and 'y' position of the ellipsis glyph.
+            Vector2& position = *(elidedPositionsBuffer + indexOfFirstGlyph);
 
-        // Add the ellipsis glyph.
-        bool       inserted              = false;
-        float      removedGlypsWidth     = 0.f;
-        Length     numberOfRemovedGlyphs = 0u;
-        GlyphIndex index                 = numberOfLaidOutGlyphs - 1u;
+            position.x = ellipsisGlyph.xBearing;
+            position.y = -ellipsisLine->ascender + controlSize.height - ellipsisGlyph.yBearing;
 
-        // The ellipsis glyph has to fit in the place where the last glyph(s) is(are) removed.
-        while(!inserted)
-        {
-          const GlyphInfo& glyphToRemove = *(elidedGlyphsBuffer + index);
+            // Replace the glyph by the ellipsis glyph and resize the buffers.
+            glyphToRemove = ellipsisGlyph;
 
-          if(0u != glyphToRemove.fontId)
-          {
-            // i.e. The font id of the glyph shaped from the '\n' character is zero.
+            mElidedGlyphs.Resize(1u);
+            mElidedLayout.Resize(1u);
 
-            // Need to reshape the glyph as the font may be different in size.
-            const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph(fontClient.GetPointSize(glyphToRemove.fontId));
+            mEndIndexOfElidedGlyphs = mStartIndexOfElidedGlyphs = mFirstMiddleIndexOfElidedGlyphs = mSecondMiddleIndexOfElidedGlyphs = indexOfFirstGlyph;
+
+            return;
+          }
+
+          // firstPenX, penY and firstPenSet are used to position the ellipsis glyph if needed.
+          float firstPenX   = 0.f; // Used if rtl text is elided.
+          float penY        = 0.f;
+          bool  firstPenSet = false;
+
+          // Add the ellipsis glyph.
+          bool       inserted              = false;
+          float      removedGlypsWidth     = 0.f;
+          Length     numberOfRemovedGlyphs = 0u;
+          GlyphIndex indexOfEllipsis       = startIndexOfEllipsis;
+
+          // Tail Mode: start by the end of line.
+          bool isTailMode = (ellipsisPosition == DevelText::EllipsisPosition::END) ||
+                            (ellipsisPosition == DevelText::EllipsisPosition::MIDDLE && numberOfLines != 1u);
 
-            if(!firstPenSet || EqualsZero(glyphToRemove.advance))
+          // The ellipsis glyph has to fit in the place where the last glyph(s) is(are) removed.
+          while(!inserted)
+          {
+            const GlyphInfo& glyphToRemove = *(elidedGlyphsBuffer + indexOfEllipsis);
+
+            if(0u != glyphToRemove.fontId)
             {
-              const Vector2& position = *(elidedPositionsBuffer + index);
+              // i.e. The font id of the glyph shaped from the '\n' character is zero.
 
-              // Calculates the penY of the current line. It will be used to position the ellipsis glyph.
-              penY = position.y + glyphToRemove.yBearing;
+              // Need to reshape the glyph as the font may be different in size.
+              const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph(fontClient.GetPointSize(glyphToRemove.fontId));
 
-              // Calculates the first penX which will be used if rtl text is elided.
-              firstPenX = position.x - glyphToRemove.xBearing;
-              if(firstPenX < -ellipsisGlyph.xBearing)
+              if(!firstPenSet)
               {
-                // Avoids to exceed the bounding box when rtl text is elided.
-                firstPenX = -ellipsisGlyph.xBearing;
-              }
+                const Vector2& position = *(elidedPositionsBuffer + indexOfEllipsis);
 
-              removedGlypsWidth = -ellipsisGlyph.xBearing;
+                // Calculates the penY of the current line. It will be used to position the ellipsis glyph.
+                penY = position.y + glyphToRemove.yBearing;
+
+                // Calculates the first penX which will be used if rtl text is elided.
+                firstPenX = position.x - glyphToRemove.xBearing;
+                if(firstPenX < -ellipsisGlyph.xBearing)
+                {
+                  // Avoids to exceed the bounding box when rtl text is elided.
+                  firstPenX = -ellipsisGlyph.xBearing;
+                }
+
+                removedGlypsWidth = -ellipsisGlyph.xBearing;
 
-              if(!EqualsZero(firstPenX))
-              {
                 firstPenSet = true;
               }
-            }
 
-            removedGlypsWidth += std::min(glyphToRemove.advance, (glyphToRemove.xBearing + glyphToRemove.width));
+              removedGlypsWidth += std::min(glyphToRemove.advance, (glyphToRemove.xBearing + glyphToRemove.width));
 
-            // Calculate the width of the ellipsis glyph and check if it fits.
-            const float ellipsisGlyphWidth = ellipsisGlyph.width + ellipsisGlyph.xBearing;
+              // Calculate the width of the ellipsis glyph and check if it fits.
+              const float ellipsisGlyphWidth = ellipsisGlyph.width + ellipsisGlyph.xBearing;
 
-            // If it is the last glyph to remove, add the ellipsis glyph without checking its width.
-            if((ellipsisGlyphWidth < removedGlypsWidth) || (index == 0u))
-            {
-              GlyphInfo& glyphInfo = *(elidedGlyphsBuffer + index);
-              Vector2&   position  = *(elidedPositionsBuffer + index);
-              position.x -= (0.f > glyphInfo.xBearing) ? glyphInfo.xBearing : 0.f;
+              // If it is the last glyph to remove, add the ellipsis glyph without checking its width.
+              if((ellipsisGlyphWidth < removedGlypsWidth) || (isTailMode ? (indexOfEllipsis == 0u) : (indexOfEllipsis == numberOfGlyphs - 1u)))
+              {
+                GlyphInfo& glyphInfo = *(elidedGlyphsBuffer + indexOfEllipsis);
+                Vector2&   position  = *(elidedPositionsBuffer + indexOfEllipsis);
+                position.x -= (0.f > glyphInfo.xBearing) ? glyphInfo.xBearing : 0.f;
 
-              // Replace the glyph by the ellipsis glyph.
-              glyphInfo = ellipsisGlyph;
+                // Replace the glyph by the ellipsis glyph.
+                glyphInfo = ellipsisGlyph;
 
-              // Change the 'x' and 'y' position of the ellipsis glyph.
-              if(position.x > firstPenX)
-              {
-                position.x = firstPenX;
-                if(ellipsisGlyphWidth < removedGlypsWidth)
+                // Change the 'x' and 'y' position of the ellipsis glyph.
+                if(position.x > firstPenX)
                 {
-                  position.x += removedGlypsWidth - ellipsisGlyphWidth;
+                  position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth;
                 }
-              }
 
-              position.x += ellipsisGlyph.xBearing;
-              position.y = penY - ellipsisGlyph.yBearing;
+                position.x += ellipsisGlyph.xBearing;
+                position.y = penY - ellipsisGlyph.yBearing;
 
-              inserted = true;
+                inserted = true;
+              }
             }
-          }
 
-          if(!inserted)
+            if(!inserted)
+            {
+              if(!isTailMode && indexOfEllipsis < numberOfGlyphs - 1u)
+              {
+                // Tail Mode: remove glyphs from startIndexOfEllipsis then decrement indexOfEllipsis, until arrive to index zero.
+                ++indexOfEllipsis;
+              }
+              else if(isTailMode && indexOfEllipsis > 0u)
+              {
+                // Not Tail Mode: remove glyphs from startIndexOfEllipsis then increase indexOfEllipsis, until arrive to last index (numberOfGlyphs - 1u).
+                --indexOfEllipsis;
+              }
+              else
+              {
+                // No space for the ellipsis.
+                inserted = true;
+              }
+              ++numberOfRemovedGlyphs;
+            }
+          } // while( !inserted )
+
+          //Reduce size, shift glyphs and start from ellipsis glyph
+          Length numberOfElidedGlyphs = numberOfActualLaidOutGlyphs - numberOfRemovedGlyphs;
+          mElidedGlyphs.Resize(numberOfElidedGlyphs);
+          mElidedLayout.Resize(numberOfElidedGlyphs);
+
+          if(ellipsisPosition == DevelText::EllipsisPosition::START)
           {
-            if(index > 0u)
+            // 'Shifts' glyphs after ellipsis glyph and 'Removes' before ellipsis glyph
+            memcpy(elidedGlyphsBuffer, elidedGlyphsBuffer + indexOfEllipsis, numberOfElidedGlyphs * sizeof(GlyphInfo));
+            memcpy(elidedPositionsBuffer, elidedPositionsBuffer + indexOfEllipsis, numberOfElidedGlyphs * sizeof(Vector2));
+
+            mStartIndexOfElidedGlyphs = mFirstMiddleIndexOfElidedGlyphs = mSecondMiddleIndexOfElidedGlyphs = indexOfEllipsis;
+          }
+          else if(ellipsisPosition == DevelText::EllipsisPosition::MIDDLE)
+          {
+            // 'Shifts and connects' glyphs before and after ellipsis glyph and 'Removes' in-between.
+            bool isOnlySecondHalf = false;
+
+            if(isTailMode)
+            {
+              mFirstMiddleIndexOfElidedGlyphs = indexOfEllipsis;
+              if(ellipsisNextLine != nullptr)
+              {
+                mSecondMiddleIndexOfElidedGlyphs = ellipsisNextLine->glyphRun.glyphIndex;
+              }
+              else
+              {
+                mEndIndexOfElidedGlyphs = mSecondMiddleIndexOfElidedGlyphs = mFirstMiddleIndexOfElidedGlyphs;
+              }
+            }
+            else
             {
-              --index;
+              mFirstMiddleIndexOfElidedGlyphs  = (ellipsisLine->glyphRun.numberOfGlyphs > 0u) ? (ellipsisLine->glyphRun.glyphIndex + ellipsisLine->glyphRun.numberOfGlyphs - 1u) : (ellipsisLine->glyphRun.glyphIndex);
+              mSecondMiddleIndexOfElidedGlyphs = indexOfEllipsis;
+              isOnlySecondHalf                 = ellipsisLine->glyphRun.numberOfGlyphs == 0u && ellipsisLine->glyphRunSecondHalf.numberOfGlyphs > 0u;
+            }
+
+            if(isOnlySecondHalf)
+            {
+              Length numberOfSecondHalfGlyphs = numberOfElidedGlyphs - mFirstMiddleIndexOfElidedGlyphs;
+
+              //Copy elided glyphs after the ellipsis glyph.
+              memcpy(elidedGlyphsBuffer + mFirstMiddleIndexOfElidedGlyphs, elidedGlyphsBuffer + mSecondMiddleIndexOfElidedGlyphs, numberOfSecondHalfGlyphs * sizeof(GlyphInfo));
+              memcpy(elidedPositionsBuffer + mFirstMiddleIndexOfElidedGlyphs, elidedPositionsBuffer + mSecondMiddleIndexOfElidedGlyphs, numberOfSecondHalfGlyphs * sizeof(Vector2));
             }
             else
             {
-              // No space for the ellipsis.
-              inserted = true;
+              Length numberOfSecondHalfGlyphs = numberOfElidedGlyphs - mFirstMiddleIndexOfElidedGlyphs + 1u;
+
+              //Copy elided glyphs after the ellipsis glyph.
+              memcpy(elidedGlyphsBuffer + mFirstMiddleIndexOfElidedGlyphs + 1u, elidedGlyphsBuffer + mSecondMiddleIndexOfElidedGlyphs, numberOfSecondHalfGlyphs * sizeof(GlyphInfo));
+              memcpy(elidedPositionsBuffer + mFirstMiddleIndexOfElidedGlyphs + 1u, elidedPositionsBuffer + mSecondMiddleIndexOfElidedGlyphs, numberOfSecondHalfGlyphs * sizeof(Vector2));
             }
-            ++numberOfRemovedGlyphs;
           }
-        } // while( !inserted )
-
-        // 'Removes' all the glyphs after the ellipsis glyph.
-        const Length numberOfGlyphs = numberOfLaidOutGlyphs - numberOfRemovedGlyphs;
-        mElidedGlyphs.Resize(numberOfGlyphs);
-        mElidedLayout.Resize(numberOfGlyphs);
+          else // DevelText::EllipsisPosition::END
+          {
+            // 'Removes' all the glyphs after the ellipsis glyph.
+            mEndIndexOfElidedGlyphs = indexOfEllipsis;
+          }
+        }
       }
     }
   }
index e51a075..fd83b62 100644 (file)
@@ -81,11 +81,16 @@ public:
   Text::VerticalAlignment::Type GetVerticalAlignment() const override;
 
   /**
- * @copydoc ModelInterface::GetVerticalLineAlignment()
- */
 * @copydoc ModelInterface::GetVerticalLineAlignment()
 */
   DevelText::VerticalLineAlignment::Type GetVerticalLineAlignment() const override;
 
   /**
+  * @copydoc ModelInterface::GetEllipsisPosition()
+  */
+  DevelText::EllipsisPosition::Type GetEllipsisPosition() const override;
+
+  /**
    * @copydoc ModelInterface::IsTextElideEnabled()
    */
   bool IsTextElideEnabled() const override;
@@ -116,6 +121,26 @@ public:
   Length GetNumberOfGlyphs() const override;
 
   /**
+   * @copydoc ModelInterface::GetStartIndexOfElidedGlyphs()
+   */
+  GlyphIndex GetStartIndexOfElidedGlyphs() const override;
+
+  /**
+   * @copydoc ModelInterface::GetEndIndexOfElidedGlyphs()
+   */
+  GlyphIndex GetEndIndexOfElidedGlyphs() const override;
+
+  /**
+   * @copydoc ModelInterface::GetFirstMiddleIndexOfElidedGlyphs()
+   */
+  GlyphIndex GetFirstMiddleIndexOfElidedGlyphs() const override;
+
+  /**
+   * @copydoc ModelInterface::GetSecondMiddleIndexOfElidedGlyphs()
+   */
+  GlyphIndex GetSecondMiddleIndexOfElidedGlyphs() const override;
+
+  /**
    * @copydoc ModelInterface::GetGlyphs()
    */
   const GlyphInfo* const GetGlyphs() const override;
@@ -236,20 +261,26 @@ public:
   Length GetHyphensCount() const override;
 
   /**
-   * @brief Does the text elide.
+   * @brief Does the text elide at the end, start or middle of text according to ellipsis position
    *
    * It stores a copy of the visible glyphs and removes as many glyphs as needed
-   * from the last visible line to add the ellipsis glyph.
+   * from the last visible line to add the ellipsis glyph in END case,
+   * from the first visible line to add the ellipsis glyph in START case,
+   * between the first and last visible lines to add the ellipsis glyph.
    *
    * It stores as well a copy of the positions for each visible glyph.
    */
   void ElideGlyphs();
 
 private:
-  const ModelInterface* const mModel;            ///< Pointer to the text's model.
-  Vector<GlyphInfo>           mElidedGlyphs;     ///< Stores the glyphs of the elided text.
-  Vector<Vector2>             mElidedLayout;     ///< Stores the positions of each glyph of the elided text.
-  bool                        mIsTextElided : 1; ///< Whether the text has been elided.
+  const ModelInterface* const mModel;                           ///< Pointer to the text's model.
+  Vector<GlyphInfo>           mElidedGlyphs;                    ///< Stores the glyphs of the elided text.
+  Vector<Vector2>             mElidedLayout;                    ///< Stores the positions of each glyph of the elided text.
+  bool                        mIsTextElided : 1;                ///< Whether the text has been elided.
+  GlyphIndex                  mStartIndexOfElidedGlyphs;        ///< The start index of elided glyphs.
+  GlyphIndex                  mEndIndexOfElidedGlyphs;          ///< The end index of elided glyphs.
+  GlyphIndex                  mFirstMiddleIndexOfElidedGlyphs;  ///< The first end index of elided glyphs, index before ellipsis of middle.
+  GlyphIndex                  mSecondMiddleIndexOfElidedGlyphs; ///< The second end index of elided glyphs, index of ellipsis of middle.
 };
 
 } // namespace Text
index decbfc1..4c71934 100644 (file)
@@ -544,6 +544,7 @@ bool Controller::Relayouter::DoRelayout(Controller& controller, const Size& size
 
     // Update the ellipsis
     bool elideTextEnabled = impl.mModel->mElideEnabled;
+    auto ellipsisPosition = impl.mModel->mEllipsisPosition;
 
     if(NULL != impl.mEventData)
     {
@@ -570,7 +571,8 @@ bool Controller::Relayouter::DoRelayout(Controller& controller, const Size& size
     viewUpdated               = impl.mLayoutEngine.LayoutText(layoutParameters,
                                                 newLayoutSize,
                                                 elideTextEnabled,
-                                                isAutoScrollEnabled);
+                                                isAutoScrollEnabled,
+                                                ellipsisPosition);
     impl.mIsAutoScrollEnabled = isAutoScrollEnabled;
 
     viewUpdated = viewUpdated || (newLayoutSize != layoutSize);
index d78f275..304276c 100644 (file)
@@ -459,6 +459,7 @@ Text::LineWrap::Mode Controller::GetLineWrapMode() const
 void Controller::SetTextElideEnabled(bool enabled)
 {
   mImpl->mModel->mElideEnabled = enabled;
+  mImpl->mModel->mVisualModel->SetTextElideEnabled(enabled);
 }
 
 bool Controller::IsTextElideEnabled() const
@@ -1719,6 +1720,17 @@ void Controller::SetVerticalLineAlignment(Toolkit::DevelText::VerticalLineAlignm
   mImpl->mModel->mVerticalLineAlignment = alignment;
 }
 
+Toolkit::DevelText::EllipsisPosition::Type Controller::GetEllipsisPosition() const
+{
+  return mImpl->mModel->GetEllipsisPosition();
+}
+
+void Controller::SetEllipsisPosition(Toolkit::DevelText::EllipsisPosition::Type ellipsisPosition)
+{
+  mImpl->mModel->mEllipsisPosition = ellipsisPosition;
+  mImpl->mModel->mVisualModel->SetEllipsisPosition(ellipsisPosition);
+}
+
 // public : Relayout.
 
 Controller::UpdateTextType Controller::Relayout(const Size& size, Dali::LayoutDirection::Type layoutDirection)
index 5c1c9e2..73f132b 100644 (file)
@@ -1429,6 +1429,18 @@ public: // Queries & retrieves.
   void SetVerticalLineAlignment(Toolkit::DevelText::VerticalLineAlignment::Type alignment);
 
   /**
+   * @brief Retrieves ellipsis position
+   * @return The ellipsis position
+   */
+  Toolkit::DevelText::EllipsisPosition::Type GetEllipsisPosition() const;
+
+  /**
+   * @brief Sets ellipsis position
+   * @param[in] ellipsisPosition The ellipsis position for the text
+   */
+  void SetEllipsisPosition(Toolkit::DevelText::EllipsisPosition::Type ellipsisPosition);
+
+  /**
    * @brief Retrieves ignoreSpaceAfterText value from model
    * @return The value of ignoreSpaceAfterText
    */
index 11ff5c6..ebb567d 100644 (file)
@@ -48,6 +48,13 @@ DALI_ENUM_TO_STRING_TABLE_BEGIN(LINE_WRAP_MODE)
   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Text::LineWrap, WORD)
   DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::Text::LineWrap, CHARACTER)
 DALI_ENUM_TO_STRING_TABLE_END(LINE_WRAP_MODE)
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN(ELLIPSIS_POSITION_TYPE)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::DevelText::EllipsisPosition, END)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::DevelText::EllipsisPosition, START)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::DevelText::EllipsisPosition, MIDDLE)
+DALI_ENUM_TO_STRING_TABLE_END(ELLIPSIS_POSITION_TYPE)
+
 } // namespace
 
 bool GetHorizontalAlignmentEnumeration(const Property::Value& propertyValue, Toolkit::Text::HorizontalAlignment::Type& alignment)
@@ -79,6 +86,11 @@ const char* GetVerticalAlignmentString(const Toolkit::Text::VerticalAlignment::T
                                                                                      VERTICAL_ALIGNMENT_TYPE_TABLE_COUNT);
 }
 
+bool GetEllipsisPositionTypeEnumeration(const Property::Value& propertyValue, Toolkit::DevelText::EllipsisPosition::Type& ellipsisPositionType)
+{
+  return Scripting::GetEnumerationProperty(propertyValue, ELLIPSIS_POSITION_TYPE_TABLE, ELLIPSIS_POSITION_TYPE_TABLE_COUNT, ellipsisPositionType);
+}
+
 } // namespace Text
 
 } // namespace Toolkit
index bb72e98..af71f7d 100644 (file)
@@ -24,6 +24,8 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/text/text-enumerations.h>
 
+// DEVEL INCLUDES
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
 namespace Dali
 {
 namespace Toolkit
@@ -68,6 +70,14 @@ const char* GetHorizontalAlignmentString(const Toolkit::Text::HorizontalAlignmen
  */
 const char* GetVerticalAlignmentString(const Toolkit::Text::VerticalAlignment::Type& alignment);
 
+/**
+ * @brief Get the ellipsis-location-type from the provided property value.
+ * @param[in] propertyValue The source value (which can be a Property::INTEGER or Property::STRING type)
+ * @param[out] ellipsisPositionType The resulting ellipsisPositionType from the given source
+ * @return true if the resulting ellipsisPositionType has been updated
+ */
+bool GetEllipsisPositionTypeEnumeration(const Property::Value& propertyValue, Toolkit::DevelText::EllipsisPosition::Type& ellipsisPositionType);
+
 } // namespace Text
 
 } // namespace Toolkit
index 928c3f0..d9520f1 100644 (file)
@@ -90,6 +90,13 @@ public:
   virtual DevelText::VerticalLineAlignment::Type GetVerticalLineAlignment() const = 0;
 
   /**
+   * @brief Retrieves ellipsis position for text.
+   *
+   * @return The ellipsis position.
+   */
+  virtual DevelText::EllipsisPosition::Type GetEllipsisPosition() const = 0;
+
+  /**
    * @brief Whether the text elide property is enabled.
    *
    * @return @e true if the text elide property is enabled, @e false otherwise.
@@ -132,6 +139,34 @@ public:
   virtual Length GetNumberOfGlyphs() const = 0;
 
   /**
+   * @brief Retrieves the start index of laid-out glyphs.
+   *
+   * @return The start index of laid-out glyphs.
+   */
+  virtual GlyphIndex GetStartIndexOfElidedGlyphs() const = 0;
+
+  /**
+   * @brief Retrieves the end index of laid-out glyphs.
+   *
+   * @return The end index of laid-out glyphs.
+   */
+  virtual GlyphIndex GetEndIndexOfElidedGlyphs() const = 0;
+
+  /**
+   * @brief Retrieves the first middle index of elided glyphs, index before ellipsis of middle.
+   *
+   * @return The first middle index of elided glyphs, index before ellipsis of middle.
+   */
+  virtual GlyphIndex GetFirstMiddleIndexOfElidedGlyphs() const = 0;
+
+  /**
+   * @brief Retrieves the second middle index of elided glyphs, index of ellipsis of middle.
+   *
+   * @return The second middle index of elided glyphs, index of ellipsis of middle.
+   */
+  virtual GlyphIndex GetSecondMiddleIndexOfElidedGlyphs() const = 0;
+
+  /**
    * @brief Retrieves the laid-out glyphs.
    *
    * @return A pointer to the vector with the laid-out glyphs.
index afc9ed0..4c3e3f0 100644 (file)
@@ -67,6 +67,11 @@ DevelText::VerticalLineAlignment::Type Model::GetVerticalLineAlignment() const
   return mVerticalLineAlignment;
 }
 
+DevelText::EllipsisPosition::Type Model::GetEllipsisPosition() const
+{
+  return mEllipsisPosition;
+}
+
 bool Model::IsTextElideEnabled() const
 {
   return mElideEnabled;
@@ -97,6 +102,26 @@ Length Model::GetNumberOfGlyphs() const
   return mVisualModel->mGlyphs.Count();
 }
 
+GlyphIndex Model::GetStartIndexOfElidedGlyphs() const
+{
+  return mVisualModel->GetStartIndexOfElidedGlyphs();
+}
+
+GlyphIndex Model::GetEndIndexOfElidedGlyphs() const
+{
+  return mVisualModel->GetEndIndexOfElidedGlyphs();
+}
+
+GlyphIndex Model::GetFirstMiddleIndexOfElidedGlyphs() const
+{
+  return mVisualModel->GetFirstMiddleIndexOfElidedGlyphs();
+}
+
+GlyphIndex Model::GetSecondMiddleIndexOfElidedGlyphs() const
+{
+  return mVisualModel->GetSecondMiddleIndexOfElidedGlyphs();
+}
+
 const GlyphInfo* const Model::GetGlyphs() const
 {
   return mVisualModel->mGlyphs.Begin();
@@ -229,7 +254,8 @@ Model::Model()
   mAlignmentOffset(0.0f),
   mElideEnabled(false),
   mIgnoreSpacesAfterText(true),
-  mMatchLayoutDirection(DevelText::MatchLayoutDirection::INHERIT)
+  mMatchLayoutDirection(DevelText::MatchLayoutDirection::INHERIT),
+  mEllipsisPosition(DevelText::EllipsisPosition::END)
 {
   mLogicalModel = LogicalModel::New();
   mVisualModel  = VisualModel::New();
index 139b8a3..280b63d 100644 (file)
@@ -83,6 +83,11 @@ public:
   DevelText::VerticalLineAlignment::Type GetVerticalLineAlignment() const override;
 
   /**
+   * @copydoc ModelInterface::GetEllipsisPosition()
+   */
+  DevelText::EllipsisPosition::Type GetEllipsisPosition() const override;
+
+  /**
    * @copydoc ModelInterface::IsTextElideEnabled()
    */
   bool IsTextElideEnabled() const override;
@@ -113,6 +118,26 @@ public:
   Length GetNumberOfGlyphs() const override;
 
   /**
+   * @copydoc ModelInterface::GetStartIndexOfElidedGlyphs()
+   */
+  GlyphIndex GetStartIndexOfElidedGlyphs() const override;
+
+  /**
+   * @copydoc ModelInterface::GetEndIndexOfElidedGlyphs()
+   */
+  GlyphIndex GetEndIndexOfElidedGlyphs() const override;
+
+  /**
+   * @copydoc ModelInterface::GetFirstMiddleIndexOfElidedGlyphs()
+   */
+  GlyphIndex GetFirstMiddleIndexOfElidedGlyphs() const override;
+
+  /**
+   * @copydoc ModelInterface::GetSecondMiddleIndexOfElidedGlyphs()
+   */
+  GlyphIndex GetSecondMiddleIndexOfElidedGlyphs() const override;
+
+  /**
    * @copydoc ModelInterface::GetGlyphs()
    */
   const GlyphInfo* const GetGlyphs() const override;
@@ -267,6 +292,7 @@ public:
   bool                                   mElideEnabled : 1;          ///< Whether the text's elide is enabled.
   bool                                   mIgnoreSpacesAfterText : 1; ///< Whether ignoring spaces after text or not. Default is true.
   DevelText::MatchLayoutDirection        mMatchLayoutDirection;      ///< Whether to match text alignment with layout direction or not.
+  DevelText::EllipsisPosition::Type      mEllipsisPosition;          ///< Where is the location the text elide
 };
 
 } // namespace Text
index ee4c306..24994bf 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
 #include <dali-toolkit/internal/text/text-definitions.h>
 
 namespace Dali
@@ -223,6 +224,48 @@ public:
    * @return The width of the outline.
    */
   virtual uint16_t GetOutlineWidth() const = 0;
+
+  /**
+   * @brief Retrieves ellipsis position for text.
+   *
+   * @return The ellipsis position.
+   */
+  virtual DevelText::EllipsisPosition::Type GetEllipsisPosition() const = 0;
+
+  /**
+   * @brief Whether the text elide property is enabled.
+   *
+   * @return @e true if the text elide property is enabled, @e false otherwise.
+   */
+  virtual bool IsTextElideEnabled() const = 0;
+
+  /**
+   * @brief Retrieves the start index of laid-out glyphs.
+   *
+   * @return The start index of laid-out glyphs.
+   */
+  virtual GlyphIndex GetStartIndexOfElidedGlyphs() const = 0;
+
+  /**
+   * @brief Retrieves the end index of laid-out glyphs.
+   *
+   * @return The end index of laid-out glyphs.
+   */
+  virtual GlyphIndex GetEndIndexOfElidedGlyphs() const = 0;
+
+  /**
+   * @brief Retrieves the first middle index of elided glyphs, index before ellipsis of middle.
+   *
+   * @return The first middle index of elided glyphs, index before ellipsis of middle.
+   */
+  virtual GlyphIndex GetFirstMiddleIndexOfElidedGlyphs() const = 0;
+
+  /**
+   * @brief Retrieves the second middle index of elided glyphs, index of ellipsis of middle.
+   *
+   * @return The second middle index of elided glyphs, index of ellipsis of middle.
+   */
+  virtual GlyphIndex GetSecondMiddleIndexOfElidedGlyphs() const = 0;
 };
 
 } // namespace Text
index 8439927..f8a2722 100644 (file)
@@ -21,6 +21,7 @@
 // EXTERNAL INCLUDES
 #include <dali/devel-api/text-abstraction/font-client.h>
 #include <dali/public-api/math/vector2.h>
+#include <memory.h>
 
 namespace Dali
 {
@@ -95,30 +96,77 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
                        GlyphIndex glyphIndex,
                        Length     numberOfGlyphs) const
 {
-  Length numberOfLaidOutGlyphs = 0u;
+  Length numberOfLaidOutGlyphs       = 0u;
+  Length numberOfActualLaidOutGlyphs = 0u;
 
   if(mImpl->mVisualModel)
   {
+    bool                              textElided       = false;
+    DevelText::EllipsisPosition::Type ellipsisPosition = GetEllipsisPosition();
+
+    //Reset indices of ElidedGlyphs
+    mImpl->mVisualModel->SetStartIndexOfElidedGlyphs(0u);
+    mImpl->mVisualModel->SetEndIndexOfElidedGlyphs(numberOfGlyphs);
+    mImpl->mVisualModel->SetFirstMiddleIndexOfElidedGlyphs(0u);
+    mImpl->mVisualModel->SetSecondMiddleIndexOfElidedGlyphs(0u);
+
     // If ellipsis is enabled, the number of glyphs the layout engine has laid out may be less than 'numberOfGlyphs'.
     // Check the last laid out line to know if the layout engine elided some text.
 
     const Length numberOfLines = mImpl->mVisualModel->mLines.Count();
     if(numberOfLines > 0u)
     {
-      const LineRun& lastLine = *(mImpl->mVisualModel->mLines.Begin() + (numberOfLines - 1u));
+      const LineRun* const lines = mImpl->mVisualModel->mLines.Begin();
+
+      //Get line of ellipsis
+      const LineRun* ellipsisLine     = nullptr;
+      const LineRun* ellipsisNextLine = nullptr;
+      bool           hasEllipsis      = false;
+      for(Length lineIndex = 0; lineIndex < numberOfLines; lineIndex++)
+      {
+        const LineRun* line = (lines + lineIndex);
+        if(line->ellipsis)
+        {
+          ellipsisLine = line;
+          hasEllipsis  = true;
+          if(lineIndex < numberOfLines - 1u)
+          {
+            ellipsisNextLine = (lines + lineIndex + 1u);
+          }
+          break;
+        }
+      }
 
       // If ellipsis is enabled, calculate the number of laid out glyphs.
       // Otherwise use the given number of glyphs.
-      if(lastLine.ellipsis)
+      if(hasEllipsis)
       {
-        numberOfLaidOutGlyphs = lastLine.glyphRun.glyphIndex + lastLine.glyphRun.numberOfGlyphs;
+        textElided            = true;
+        numberOfLaidOutGlyphs = numberOfGlyphs;
+
+        if(ellipsisPosition == DevelText::EllipsisPosition::START)
+        {
+          numberOfActualLaidOutGlyphs = numberOfGlyphs - ellipsisLine->glyphRun.glyphIndex;
+        }
+        else if(ellipsisPosition == DevelText::EllipsisPosition::MIDDLE)
+        {
+          numberOfActualLaidOutGlyphs = 0u;
+          for(Length lineIndex = 0u; lineIndex < numberOfLines; lineIndex++)
+          {
+            numberOfActualLaidOutGlyphs += lines[lineIndex].glyphRun.numberOfGlyphs + lines[lineIndex].glyphRunSecondHalf.numberOfGlyphs;
+          }
+        }
+        else // DevelText::EllipsisPosition::END
+        {
+          numberOfActualLaidOutGlyphs = ellipsisLine->glyphRun.glyphIndex + ellipsisLine->glyphRun.numberOfGlyphs;
+        }
       }
       else
       {
-        numberOfLaidOutGlyphs = numberOfGlyphs;
+        numberOfActualLaidOutGlyphs = numberOfLaidOutGlyphs = numberOfGlyphs;
       }
 
-      if(0u < numberOfLaidOutGlyphs)
+      if(0u < numberOfActualLaidOutGlyphs)
       {
         // Retrieve from the visual model the glyphs and positions.
         mImpl->mVisualModel->GetGlyphs(glyphs,
@@ -131,11 +179,11 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
 
         // Get the lines for the given range of glyphs.
         // The lines contain the alignment offset which needs to be added to the glyph's position.
-        LineIndex firstLine     = 0u;
-        Length    numberOfLines = 0u;
+        LineIndex firstLineIndex = 0u;
+        Length    numberOfLines  = 0u;
         mImpl->mVisualModel->GetNumberOfLines(glyphIndex,
                                               numberOfLaidOutGlyphs,
-                                              firstLine,
+                                              firstLineIndex,
                                               numberOfLines);
 
         Vector<LineRun> lines;
@@ -147,11 +195,11 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
                                                   numberOfLaidOutGlyphs);
 
         // Get the first line for the given glyph range.
-        LineIndex lineIndex = firstLine;
+        LineIndex lineIndex = firstLineIndex;
         LineRun*  line      = lineBuffer + lineIndex;
 
         // Index of the last glyph of the line.
-        GlyphIndex lastGlyphIndexOfLine = line->glyphRun.glyphIndex + line->glyphRun.numberOfGlyphs - 1u;
+        GlyphIndex lastGlyphIndexOfLine = (line->isSplitToTwoHalves ? line->glyphRunSecondHalf.glyphIndex + line->glyphRunSecondHalf.numberOfGlyphs : line->glyphRun.glyphIndex + line->glyphRun.numberOfGlyphs) - 1u;
 
         // Add the alignment offset to the glyph's position.
 
@@ -175,37 +223,76 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
               line          = lineBuffer + lineIndex;
               minLineOffset = std::min(minLineOffset, line->alignmentOffset);
 
-              lastGlyphIndexOfLine = line->glyphRun.glyphIndex + line->glyphRun.numberOfGlyphs - 1u;
+              lastGlyphIndexOfLine = (line->isSplitToTwoHalves ? line->glyphRunSecondHalf.glyphIndex + line->glyphRunSecondHalf.numberOfGlyphs : line->glyphRun.glyphIndex + line->glyphRun.numberOfGlyphs) - 1u;
 
               penY += line->ascender;
             }
           }
         }
 
+        // Set index where to set Ellipsis according to the selected position of Ellipsis.
+        // Start with this index to replace its glyph by Ellipsis, if the width  is not enough, then remove more glyphs.
+        GlyphIndex startIndexOfEllipsis = 0u;
+        if(hasEllipsis)
+        {
+          if(ellipsisPosition == DevelText::EllipsisPosition::START)
+          {
+            // It's the fisrt glyph in line.
+            startIndexOfEllipsis = ellipsisLine->glyphRun.glyphIndex;
+          }
+          else if(ellipsisPosition == DevelText::EllipsisPosition::MIDDLE)
+          {
+            // It's the second middle of the line in case the line split to two halves.
+            // Otherwise it's It's the last glyph in line (line before all removed lines).
+            startIndexOfEllipsis = ellipsisLine->isSplitToTwoHalves ? (ellipsisLine->glyphRunSecondHalf.glyphIndex) : (ellipsisLine->glyphRun.glyphIndex + ellipsisLine->glyphRun.numberOfGlyphs - 1u);
+          }
+          else // DevelText::EllipsisPosition::END
+          {
+            // It's the last glyph in line.
+            startIndexOfEllipsis = ellipsisLine->glyphRun.glyphIndex + ellipsisLine->glyphRun.numberOfGlyphs - 1u;
+          }
+        }
+
         if(1u == numberOfLaidOutGlyphs)
         {
           // not a point try to do ellipsis with only one laid out character.
+
           return numberOfLaidOutGlyphs;
         }
 
-        if(lastLine.ellipsis)
+        if(textElided)
         {
+          const LineRun& elidedLine = *ellipsisLine;
+
           if((1u == numberOfLines) &&
-             (lastLine.ascender - lastLine.descender > mImpl->mVisualModel->mControlSize.height))
+             (elidedLine.ascender - elidedLine.descender > mImpl->mVisualModel->mControlSize.height))
           {
+            // Replace the first glyph with ellipsis glyph
+            auto indexOfFirstGlyph = (ellipsisPosition == DevelText::EllipsisPosition::START) ? startIndexOfEllipsis : 0u;
+
+            // Regardless where the location of ellipsis,in-case the hight of line is greater than control's height
+            // then replace the first glyph with ellipsis glyph.
+
             // Get the first glyph which is going to be replaced and the ellipsis glyph.
-            GlyphInfo&       glyphInfo     = *glyphs;
+            GlyphInfo&       glyphInfo     = *(glyphs + indexOfFirstGlyph);
             const GlyphInfo& ellipsisGlyph = mImpl->mFontClient.GetEllipsisGlyph(mImpl->mFontClient.GetPointSize(glyphInfo.fontId));
 
             // Change the 'x' and 'y' position of the ellipsis glyph.
-            Vector2& position = *glyphPositions;
+            Vector2& position = *(glyphPositions + indexOfFirstGlyph);
             position.x        = ellipsisGlyph.xBearing;
             position.y        = mImpl->mVisualModel->mControlSize.height - ellipsisGlyph.yBearing;
 
             // Replace the glyph by the ellipsis glyph.
             glyphInfo = ellipsisGlyph;
 
-            return 1u;
+            mImpl->mVisualModel->SetStartIndexOfElidedGlyphs(indexOfFirstGlyph);
+            mImpl->mVisualModel->SetEndIndexOfElidedGlyphs(indexOfFirstGlyph);
+            mImpl->mVisualModel->SetFirstMiddleIndexOfElidedGlyphs(indexOfFirstGlyph);
+            mImpl->mVisualModel->SetSecondMiddleIndexOfElidedGlyphs(indexOfFirstGlyph);
+
+            numberOfLaidOutGlyphs = 1u;
+
+            return numberOfLaidOutGlyphs;
           }
 
           // firstPenX, penY and firstPenSet are used to position the ellipsis glyph if needed.
@@ -217,12 +304,16 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
           bool       inserted              = false;
           float      removedGlypsWidth     = 0.f;
           Length     numberOfRemovedGlyphs = 0u;
-          GlyphIndex index                 = numberOfLaidOutGlyphs - 1u;
+          GlyphIndex indexOfEllipsis       = startIndexOfEllipsis;
+
+          // Tail Mode: start by the end of line.
+          const bool isTailMode = ellipsisPosition == DevelText::EllipsisPosition::END ||
+                                  (ellipsisPosition == DevelText::EllipsisPosition::MIDDLE && numberOfLines != 1u);
 
           // The ellipsis glyph has to fit in the place where the last glyph(s) is(are) removed.
           while(!inserted)
           {
-            const GlyphInfo& glyphToRemove = *(glyphs + index);
+            const GlyphInfo& glyphToRemove = *(glyphs + indexOfEllipsis);
 
             if(0u != glyphToRemove.fontId)
             {
@@ -233,7 +324,7 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
 
               if(!firstPenSet)
               {
-                const Vector2& position = *(glyphPositions + index);
+                const Vector2& position = *(glyphPositions + indexOfEllipsis);
 
                 // Calculates the penY of the current line. It will be used to position the ellipsis glyph.
                 penY = position.y + glyphToRemove.yBearing;
@@ -255,10 +346,10 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
 
               // Calculate the width of the ellipsis glyph and check if it fits.
               const float ellipsisGlyphWidth = ellipsisGlyph.width + ellipsisGlyph.xBearing;
-              if(ellipsisGlyphWidth < removedGlypsWidth)
+              if((ellipsisGlyphWidth < removedGlypsWidth) || (isTailMode ? (indexOfEllipsis == 0u) : (indexOfEllipsis == numberOfGlyphs - 1u)))
               {
-                GlyphInfo& glyphInfo = *(glyphs + index);
-                Vector2&   position  = *(glyphPositions + index);
+                GlyphInfo& glyphInfo = *(glyphs + indexOfEllipsis);
+                Vector2&   position  = *(glyphPositions + indexOfEllipsis);
                 position.x -= (0.f > glyphInfo.xBearing) ? glyphInfo.xBearing : 0.f;
 
                 // Replace the glyph by the ellipsis glyph.
@@ -280,9 +371,15 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
 
             if(!inserted)
             {
-              if(index > 0u)
+              if(isTailMode && indexOfEllipsis > 0u)
               {
-                --index;
+                // Tail Mode: remove glyphs from startIndexOfEllipsis then decrement indexOfEllipsis, until arrive to index zero.
+                --indexOfEllipsis;
+              }
+              else if(!isTailMode && indexOfEllipsis < numberOfLaidOutGlyphs - 1u)
+              {
+                // Not Tail Mode: remove glyphs from startIndexOfEllipsis then increase indexOfEllipsis, until arrive to last index (numberOfGlyphs - 1u).
+                ++indexOfEllipsis;
               }
               else
               {
@@ -294,7 +391,99 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
           }
 
           // 'Removes' all the glyphs after the ellipsis glyph.
-          numberOfLaidOutGlyphs -= numberOfRemovedGlyphs;
+          if(ellipsisPosition == DevelText::EllipsisPosition::MIDDLE)
+          {
+            //Reduce size, shift glyphs and start from ellipsis glyph
+            numberOfLaidOutGlyphs = numberOfActualLaidOutGlyphs - numberOfRemovedGlyphs;
+
+            GlyphIndex firstMiddleIndexOfElidedGlyphs  = 0u;
+            GlyphIndex secondMiddleIndexOfElidedGlyphs = 0u;
+
+            bool isOnlySecondHalf = false;
+            if(isTailMode)
+            {
+              // Multi-lines case with MIDDLE
+              // In case the Ellipsis in the end of line,
+              // then this index will be the firstMiddleIndex.
+              // The secondMiddleIndex will be the fisrt index in next line.
+              // But in case there is no line after Ellipsis's line then secondMiddleIndex and endIndex equal firstMiddle
+              // Example:
+              // A: are laid out glyphs in line has Ellipsis in the end.
+              // N: are laid out glyphs in lines after removed lines.
+              // R: are removed glyphs.
+              // L: are removed glyphs when removed lines.
+              // AAAAAAAAAAAA...RRR    => Here's the firstMiddleIndex (First index after last A)
+              // LLLLLLLLLLLLLLL
+              // LLLLLLLLLLLLLLL
+              // NNNNNNNNNNNNNN        => Here's the secondMiddleIndex (First N)
+              // NNNNNNNNNN
+
+              firstMiddleIndexOfElidedGlyphs = indexOfEllipsis;
+              if(ellipsisNextLine != nullptr)
+              {
+                secondMiddleIndexOfElidedGlyphs = ellipsisNextLine->glyphRun.glyphIndex;
+              }
+              else
+              {
+                secondMiddleIndexOfElidedGlyphs = firstMiddleIndexOfElidedGlyphs;
+                mImpl->mVisualModel->SetEndIndexOfElidedGlyphs(firstMiddleIndexOfElidedGlyphs);
+              }
+            }
+            else
+            {
+              // Single line case with MIDDLE
+              // In case the Ellipsis in the middle of line,
+              // Then the last index in first half will be firstMiddleIndex.
+              // And the indexOfEllipsis will be secondMiddleIndex, which is the first index in second half.
+              // Example:
+              // A: are laid out glyphs in first half of line.
+              // N: are laid out glyphs in second half of line.
+              // R: are removed glyphs.
+              // L: re removed glyphs when layouting text
+              // AAAAAAALLLLLLLLLLLRRR...NNNNN
+              // firstMiddleIndex (index of last A)
+              // secondMiddleIndex (index before first N)
+
+              firstMiddleIndexOfElidedGlyphs  = (ellipsisLine->glyphRun.numberOfGlyphs > 0u) ? (ellipsisLine->glyphRun.glyphIndex + ellipsisLine->glyphRun.numberOfGlyphs - 1u) : (ellipsisLine->glyphRun.glyphIndex);
+              secondMiddleIndexOfElidedGlyphs = indexOfEllipsis;
+              isOnlySecondHalf                = ellipsisLine->glyphRun.numberOfGlyphs == 0u && ellipsisLine->glyphRunSecondHalf.numberOfGlyphs > 0u;
+            }
+
+            mImpl->mVisualModel->SetFirstMiddleIndexOfElidedGlyphs(firstMiddleIndexOfElidedGlyphs);
+            mImpl->mVisualModel->SetSecondMiddleIndexOfElidedGlyphs(secondMiddleIndexOfElidedGlyphs);
+
+            // The number of shifted glyphs and shifting positions will be different according to Single-line or Multi-lines.
+            // isOnlySecondHalf will be true when MIDDLE Ellipsis glyph in single line.
+            if(isOnlySecondHalf)
+            {
+              Length numberOfSecondHalfGlyphs = numberOfLaidOutGlyphs - firstMiddleIndexOfElidedGlyphs;
+
+              //Copy elided glyphs after the ellipsis glyph.
+              memcpy(glyphs + firstMiddleIndexOfElidedGlyphs, glyphs + secondMiddleIndexOfElidedGlyphs, numberOfSecondHalfGlyphs * sizeof(GlyphInfo));
+              memcpy(glyphPositions + firstMiddleIndexOfElidedGlyphs, glyphPositions + secondMiddleIndexOfElidedGlyphs, numberOfSecondHalfGlyphs * sizeof(Vector2));
+            }
+            else
+            {
+              Length numberOfSecondHalfGlyphs = numberOfLaidOutGlyphs - firstMiddleIndexOfElidedGlyphs + 1u;
+
+              //Copy elided glyphs after the ellipsis glyph.
+              memcpy(glyphs + firstMiddleIndexOfElidedGlyphs + 1u, glyphs + secondMiddleIndexOfElidedGlyphs, numberOfSecondHalfGlyphs * sizeof(GlyphInfo));
+              memcpy(glyphPositions + firstMiddleIndexOfElidedGlyphs + 1u, glyphPositions + secondMiddleIndexOfElidedGlyphs, numberOfSecondHalfGlyphs * sizeof(Vector2));
+            }
+          }
+          else if(ellipsisPosition == DevelText::EllipsisPosition::START)
+          {
+            numberOfLaidOutGlyphs = numberOfActualLaidOutGlyphs - numberOfRemovedGlyphs;
+            //Copy elided glyphs after the ellipsis glyph.
+            memcpy(glyphs, glyphs + startIndexOfEllipsis + numberOfRemovedGlyphs, numberOfLaidOutGlyphs * sizeof(GlyphInfo));
+            memcpy(glyphPositions, glyphPositions + startIndexOfEllipsis + numberOfRemovedGlyphs, numberOfLaidOutGlyphs * sizeof(Vector2));
+            mImpl->mVisualModel->SetStartIndexOfElidedGlyphs(indexOfEllipsis);
+          }
+          else // DevelText::EllipsisPosition::END
+          {
+            numberOfLaidOutGlyphs = numberOfActualLaidOutGlyphs - numberOfRemovedGlyphs;
+            mImpl->mVisualModel->SetEndIndexOfElidedGlyphs(indexOfEllipsis);
+          }
         }
       }
     }
@@ -476,6 +665,83 @@ uint16_t View::GetOutlineWidth() const
   return 0u;
 }
 
+DevelText::EllipsisPosition::Type View::GetEllipsisPosition() const
+{
+  DevelText::EllipsisPosition::Type ellipsisPosition = DevelText::EllipsisPosition::END;
+  if(mImpl->mVisualModel)
+  {
+    const VisualModel& model = *mImpl->mVisualModel;
+    ellipsisPosition         = model.GetEllipsisPosition();
+  }
+
+  return ellipsisPosition;
+}
+
+bool View::IsTextElideEnabled() const
+{
+  bool isTextElideEnabled = false;
+
+  if(mImpl->mVisualModel)
+  {
+    const VisualModel& model = *mImpl->mVisualModel;
+    isTextElideEnabled       = model.IsTextElideEnabled();
+  }
+
+  return isTextElideEnabled;
+}
+
+GlyphIndex View::GetStartIndexOfElidedGlyphs() const
+{
+  GlyphIndex startIndexOfElidedGlyphs = 0u;
+
+  if(mImpl->mVisualModel)
+  {
+    const VisualModel& model = *mImpl->mVisualModel;
+    startIndexOfElidedGlyphs = model.GetStartIndexOfElidedGlyphs();
+  }
+
+  return startIndexOfElidedGlyphs;
+}
+
+GlyphIndex View::GetEndIndexOfElidedGlyphs() const
+{
+  GlyphIndex endIndexOfElidedGlyphs = 0u;
+
+  if(mImpl->mVisualModel)
+  {
+    const VisualModel& model = *mImpl->mVisualModel;
+    endIndexOfElidedGlyphs   = model.GetEndIndexOfElidedGlyphs();
+  }
+
+  return endIndexOfElidedGlyphs;
+}
+
+GlyphIndex View::GetFirstMiddleIndexOfElidedGlyphs() const
+{
+  GlyphIndex firstMiddleIndexOfElidedGlyphs = 0u;
+
+  if(mImpl->mVisualModel)
+  {
+    const VisualModel& model       = *mImpl->mVisualModel;
+    firstMiddleIndexOfElidedGlyphs = model.GetFirstMiddleIndexOfElidedGlyphs();
+  }
+
+  return firstMiddleIndexOfElidedGlyphs;
+}
+
+GlyphIndex View::GetSecondMiddleIndexOfElidedGlyphs() const
+{
+  GlyphIndex secondMiddleIndexOfElidedGlyphs = 0u;
+
+  if(mImpl->mVisualModel)
+  {
+    const VisualModel& model        = *mImpl->mVisualModel;
+    secondMiddleIndexOfElidedGlyphs = model.GetSecondMiddleIndexOfElidedGlyphs();
+  }
+
+  return secondMiddleIndexOfElidedGlyphs;
+}
+
 } // namespace Text
 
 } // namespace Toolkit
index 7c61275..62324e8 100644 (file)
@@ -167,6 +167,36 @@ public:
    */
   uint16_t GetOutlineWidth() const override;
 
+  /**
+  * @copydoc Dali::Toolkit::Text::ViewInterface::GetEllipsisPosition()
+  */
+  DevelText::EllipsisPosition::Type GetEllipsisPosition() const override;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::IsTextElideEnabled()
+   */
+  bool IsTextElideEnabled() const override;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetStartIndexOfElidedGlyphs()
+   */
+  GlyphIndex GetStartIndexOfElidedGlyphs() const override;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetEndIndexOfElidedGlyphs()
+   */
+  GlyphIndex GetEndIndexOfElidedGlyphs() const override;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetFirstMiddleIndexOfElidedGlyphs()
+   */
+  GlyphIndex GetFirstMiddleIndexOfElidedGlyphs() const override;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetSecondMiddleIndexOfElidedGlyphs()
+   */
+  GlyphIndex GetSecondMiddleIndexOfElidedGlyphs() const override;
+
 private:
   // Undefined
   View(const View& handle);
index 7edb428..5fa3843 100644 (file)
@@ -230,6 +230,12 @@ void VisualModel::GetNumberOfLines(GlyphIndex glyphIndex,
       firstLineFound = true;
       ++numberOfLines;
     }
+    else if((line.glyphRunSecondHalf.glyphIndex + line.glyphRunSecondHalf.numberOfGlyphs > glyphIndex) &&
+            (lastGlyphIndex > line.glyphRunSecondHalf.glyphIndex))
+    {
+      firstLineFound = true;
+      ++numberOfLines;
+    }
     else if(lastGlyphIndex <= line.glyphRun.glyphIndex)
     {
       // nothing else to do.
@@ -389,6 +395,36 @@ void VisualModel::SetMarkupProcessorEnabled(bool enabled)
   mMarkupProcessorEnabled = enabled;
 }
 
+void VisualModel::SetTextElideEnabled(bool enabled)
+{
+  mTextElideEnabled = enabled;
+}
+
+void VisualModel::SetEllipsisPosition(Toolkit::DevelText::EllipsisPosition::Type ellipsisPosition)
+{
+  mEllipsisPosition = ellipsisPosition;
+}
+
+void VisualModel::SetStartIndexOfElidedGlyphs(GlyphIndex startIndexOfElidedGlyphs)
+{
+  mStartIndexOfElidedGlyphs = startIndexOfElidedGlyphs;
+}
+
+void VisualModel::SetEndIndexOfElidedGlyphs(GlyphIndex endIndexOfElidedGlyphs)
+{
+  mEndIndexOfElidedGlyphs = endIndexOfElidedGlyphs;
+}
+
+void VisualModel::SetFirstMiddleIndexOfElidedGlyphs(GlyphIndex firstMiddleIndexOfElidedGlyphs)
+{
+  mFirstMiddleIndexOfElidedGlyphs = firstMiddleIndexOfElidedGlyphs;
+}
+
+void VisualModel::SetSecondMiddleIndexOfElidedGlyphs(GlyphIndex secondMiddleIndexOfElidedGlyphs)
+{
+  mSecondMiddleIndexOfElidedGlyphs = secondMiddleIndexOfElidedGlyphs;
+}
+
 const Vector4& VisualModel::GetTextColor() const
 {
   return mTextColor;
@@ -449,6 +485,36 @@ bool VisualModel::IsMarkupProcessorEnabled() const
   return mMarkupProcessorEnabled;
 }
 
+bool VisualModel::IsTextElideEnabled() const
+{
+  return mTextElideEnabled;
+}
+
+Toolkit::DevelText::EllipsisPosition::Type VisualModel::GetEllipsisPosition() const
+{
+  return mEllipsisPosition;
+}
+
+GlyphIndex VisualModel::GetStartIndexOfElidedGlyphs() const
+{
+  return mStartIndexOfElidedGlyphs;
+}
+
+GlyphIndex VisualModel::GetEndIndexOfElidedGlyphs() const
+{
+  return mEndIndexOfElidedGlyphs;
+}
+
+GlyphIndex VisualModel::GetFirstMiddleIndexOfElidedGlyphs() const
+{
+  return mFirstMiddleIndexOfElidedGlyphs;
+}
+
+GlyphIndex VisualModel::GetSecondMiddleIndexOfElidedGlyphs() const
+{
+  return mSecondMiddleIndexOfElidedGlyphs;
+}
+
 Length VisualModel::GetNumberOfUnderlineRuns() const
 {
   return mUnderlineRuns.Count();
@@ -484,10 +550,17 @@ VisualModel::VisualModel()
   mNaturalSize(),
   mLayoutSize(),
   mCachedLineIndex(0u),
+  mEllipsisPosition(DevelText::EllipsisPosition::END),
+  mStartIndexOfElidedGlyphs(0u),
+  mEndIndexOfElidedGlyphs(0u),
+  mFirstMiddleIndexOfElidedGlyphs(0u),
+  mSecondMiddleIndexOfElidedGlyphs(0u),
+  mTextElideEnabled(false),
   mUnderlineEnabled(false),
   mUnderlineColorSet(false),
   mBackgroundEnabled(false),
   mMarkupProcessorEnabled(false)
+
 {
 }
 
index c355c3c..359b695 100644 (file)
@@ -29,6 +29,9 @@
 #include <dali-toolkit/internal/text/color-run.h>
 #include <dali-toolkit/internal/text/line-run.h>
 
+// DEVEL INCLUDES
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+
 namespace Dali
 {
 namespace Toolkit
@@ -374,6 +377,89 @@ public:
    */
   bool IsMarkupProcessorEnabled() const;
 
+  /**
+   * @brief Sets ellipsis position
+   * @param[in] ellipsisPosition The ellipsis position for the text
+   */
+  void SetEllipsisPosition(Toolkit::DevelText::EllipsisPosition::Type ellipsisPosition);
+
+  /**
+   * @brief Retrieves ellipsis position for text.
+   *
+   * @return The ellipsis position.
+   */
+  Toolkit::DevelText::EllipsisPosition::Type GetEllipsisPosition() const;
+
+  /**
+   * @brief Enable or disable the text elide.
+   *
+   * @param[in] enabled Whether to enable the text elide.
+   */
+  void SetTextElideEnabled(bool enabled);
+
+  /**
+   * @brief Whether the text elide property is enabled.
+   *
+   * @return @e true if the text elide property is enabled, @e false otherwise.
+   */
+  bool IsTextElideEnabled() const;
+
+  /**
+   * @brief Sets the start index of laid-out glyphs.
+   *
+   * @param[in] startIndexOfElidedGlyphs The start index of laid-out glyphs.
+   */
+  void SetStartIndexOfElidedGlyphs(GlyphIndex startIndexOfElidedGlyphs);
+
+  /**
+   * @brief Sets the end index of elided glyphs.
+   *
+   * @param[in] endIndexOfElidedGlyphs The end index of elided glyphs.
+   */
+  void SetEndIndexOfElidedGlyphs(GlyphIndex endIndexOfElidedGlyphs);
+
+  /**
+   * @brief Sets the first middle index of elided glyphs, index before ellipsis of middle.
+   *
+   * @param[in] firstMiddleIndexOfElidedGlyphs The first middle index of elided glyphs, index before ellipsis of middle.
+   */
+  void SetFirstMiddleIndexOfElidedGlyphs(GlyphIndex firstMiddleIndexOfElidedGlyphs);
+
+  /**
+   * @brief Sets the second middle index of elided glyphs, index of ellipsis of middle.
+   *
+   * @param[in] secondMiddleIndexOfElidedGlyphs The second middle index of elided glyphs, index of ellipsis of middle.
+   */
+  void SetSecondMiddleIndexOfElidedGlyphs(GlyphIndex secondMiddleIndexOfElidedGlyphs);
+
+  /**
+   * @brief Retrieves the start index of laid-out glyphs.
+   *
+   * @return The start index of laid-out glyphs.
+   */
+  GlyphIndex GetStartIndexOfElidedGlyphs() const;
+
+  /**
+   * @brief Retrieves the end index of laid-out glyphs.
+   *
+   * @return The end index of laid-out glyphs.
+   */
+  GlyphIndex GetEndIndexOfElidedGlyphs() const;
+
+  /**
+   * @brief Retrieves the first middle index of elided glyphs, index before ellipsis of middle.
+   *
+   * @return The first middle index of elided glyphs, index before ellipsis of middle.
+   */
+  GlyphIndex GetFirstMiddleIndexOfElidedGlyphs() const;
+
+  /**
+   * @brief Retrieves the second middle index of elided glyphs, index of ellipsis of middle.
+   *
+   * @return The second middle index of elided glyphs, index of ellipsis of middle.
+   */
+  GlyphIndex GetSecondMiddleIndexOfElidedGlyphs() const;
+
 protected:
   /**
    * @brief A reference counted object may only be deleted by calling Unreference().
@@ -424,12 +510,19 @@ private:
   // Caches to increase performance in some consecutive operations.
   LineIndex mCachedLineIndex; ///< Used to increase performance in consecutive calls to GetLineOfGlyph() or GetLineOfCharacter() with consecutive glyphs or characters.
 
+  DevelText::EllipsisPosition::Type mEllipsisPosition;                ///< Where is the location the text elide
+  GlyphIndex                        mStartIndexOfElidedGlyphs;        ///< The start index of elided glyphs.
+  GlyphIndex                        mEndIndexOfElidedGlyphs;          ///< The end index of elided glyphs.
+  GlyphIndex                        mFirstMiddleIndexOfElidedGlyphs;  ///< The first end index of elided glyphs, index before ellipsis of middle.
+  GlyphIndex                        mSecondMiddleIndexOfElidedGlyphs; ///< The first end index of elided glyphs, index of ellipsis of middle.
+  bool                              mTextElideEnabled : 1;            ///< Whether the text's elide is enabled.
+
 public:
-  bool mUnderlineEnabled : 1;  ///< Underline enabled flag
-  bool mUnderlineColorSet : 1; ///< Has the underline color been explicitly set?
-  bool mBackgroundEnabled : 1; ///< Background enabled flag
-  bool mMarkupProcessorEnabled : 1; ///< Markup-processor enabled flag
-  HyphenInfo mHyphen; ///< Contains hyphen glyph info & the character index to draw hyphen after.
+  bool       mUnderlineEnabled : 1;       ///< Underline enabled flag
+  bool       mUnderlineColorSet : 1;      ///< Has the underline color been explicitly set?
+  bool       mBackgroundEnabled : 1;      ///< Background enabled flag
+  bool       mMarkupProcessorEnabled : 1; ///< Markup-processor enabled flag
+  HyphenInfo mHyphen;                     ///< Contains hyphen glyph info & the character index to draw hyphen after.
 };
 
 } // namespace Text