Fixing Bug: Caret is too big with LineSpacing 81/264281/15
authorSara Samara <sara.samara@samsung.com>
Wed, 15 Sep 2021 10:29:23 +0000 (13:29 +0300)
committerabdullah <abdullahhasan10@gmail.com>
Wed, 15 Dec 2021 15:53:31 +0000 (17:53 +0200)
***********************************************************
Description

When using LineSpacing or MinLineSize the caret size is too big and does not look good.

The primary cursor height was obtaining its height from the line height (which includes the line spacing).
I've modified it to obtain the height from the default font height.

Please use the code below to test the issue and its fix.
***********************************************************

using namespace Dali;
using namespace Dali::Toolkit;

class SimpleApp : public ConnectionTracker
{
public:
  SimpleApp(Application& application)
  : mApplication(application)
  {
    mApplication.InitSignal().Connect(this, &SimpleApp::Create);
  }

  void Create(Application& application)
  {
    Window window = application.GetWindow();
    window.SetBackgroundColor(Vector4(0.04f, 0.345f, 0.392f, 1.0f));

    mEditor = TextEditor::New();
    mEditor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
    mEditor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
    mEditor.SetProperty(Actor::Property::POSITION, Vector3(0.f, 0.0f, 0.f));
    mEditor.SetProperty(Actor::Property::SIZE, Vector2(200.f, 100.0f));
    mEditor.SetProperty(TextEditor::Property::TEXT, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n");
    mEditor.SetProperty(TextEditor::Property::ENABLE_MARKUP, true);
    mEditor.SetProperty(TextEditor::Property::POINT_SIZE, 40.0f);
    mEditor.SetBackgroundColor(Color::WHITE);
    mEditor.SetProperty( DevelTextEditor::Property::MIN_LINE_SIZE, 50.f );

    window.Add(mEditor);
  }

   bool OnButtonClicked(Button button)
  {
    if(button == mButton)
    {
      Vector3 originalSize = mEditor.GetNaturalSize();
    }
    return true;
  }

private:
  Application &mApplication;
  TextEditor mEditor;
  PushButton mButton;
  TextField mField;
};

int DALI_EXPORT_API main(int argc, char** argv)
{
  Application application = Application::New(&argc, &argv);
  SimpleApp test(application);
  application.MainLoop();

  return 0;
}

Change-Id: I8d8accbef03b69ba4e77f4f891bae08e37f93a00

15 files changed:
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-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-VisualModel.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp
dali-toolkit/internal/text/cursor-helper-functions.cpp
dali-toolkit/internal/text/cursor-helper-functions.h
dali-toolkit/internal/text/glyph-metrics-helper.cpp
dali-toolkit/internal/text/glyph-metrics-helper.h
dali-toolkit/internal/text/text-controller-impl.cpp

index 701977d..cc0288c 100755 (executable)
@@ -104,7 +104,8 @@ void CreateTextModel( const std::string& text,
                       bool markupProcessorEnabled,
                       LineWrap::Mode wrapMode,
                       bool ellipsisEnabled,
-                      DevelText::EllipsisPosition::Type ellipsisPosition)
+                      DevelText::EllipsisPosition::Type ellipsisPosition,
+                      float lineSpacing)
 {
   textModel = Model::New(); ///< Pointer to the text's model.
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
@@ -327,6 +328,7 @@ void CreateTextModel( const std::string& text,
   Layout::Engine layoutEngine;
   layoutEngine.SetMetrics( metrics );
   layoutEngine.SetLayout( Layout::Engine::MULTI_LINE_BOX );
+  layoutEngine.SetDefaultLineSpacing(lineSpacing);
 
   // Set the layout parameters.
   textModel->mHorizontalAlignment = Text::HorizontalAlignment::BEGIN;
index 0b9f592..389d72d 100644 (file)
@@ -59,6 +59,7 @@ struct LayoutOptions
  * @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.
+ * @param[in] lineSpacing The height of the line in points.
  */
 void CreateTextModel( const std::string& text,
                       const Size& textArea,
@@ -70,7 +71,8 @@ void CreateTextModel( const std::string& text,
                       bool markupProcessorEnabled,
                       LineWrap::Mode wrapMode,
                       bool ellipsisEnabled,
-                      DevelText::EllipsisPosition::Type ellipsisPosition);
+                      DevelText::EllipsisPosition::Type ellipsisPosition,
+                      float lineSpacing);
 
 /**
  * @brief Configures the text @p controller similarly to the one configured by the text-label.
index 84ecd2d..9f1d5da 100644 (file)
@@ -114,7 +114,8 @@ bool SetBidirectionalInfoTest( const SetBidirectionalInfoData& data )
                    false,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -202,7 +203,8 @@ bool GetMirroredTextTest( const GetMirroredTextData& data )
                    false,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -281,7 +283,8 @@ bool GetCharactersDirectionTest( const GetCharactersDirectionData& data )
                    data.markupProcessorEnabled,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
index a95b707..8b15ad3 100755 (executable)
@@ -121,7 +121,8 @@ bool CreateParagraphTest( const CreateParagraphData& data )
                    false,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -186,7 +187,8 @@ bool FindParagraphTest( const FindParagraphData& data )
                    false,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -240,7 +242,8 @@ bool FetchBidirectionalLineInfoTest( const FetchBidirectionalLineInfoData& data
                    false,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -289,7 +292,8 @@ bool GetLogicalCharacterIndexTest( const GetLogicalCharacterIndexData& data )
                    false,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -355,7 +359,8 @@ bool GetLogicalCursorIndexTest( const GetLogicalCursorIndexData& data )
                    false,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
index 768e58b..920a826 100755 (executable)
@@ -16,8 +16,8 @@
  */
 
 #include <iostream>
-
 #include <stdlib.h>
+#include <unistd.h>
 
 #include <dali-toolkit-test-suite-utils.h>
 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
@@ -46,6 +46,8 @@ using namespace Text;
 
 namespace
 {
+  const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+  const unsigned int DEFAULT_FONT_SIZE = 1152u;
 
 struct GetClosestLineData
 {
@@ -92,6 +94,15 @@ struct FindSelectionIndicesData
   CharacterIndex* noTextHitIndex;                 ///< The expected character index when there is no hit.
 };
 
+struct PrimaryCursorHeightData
+{
+  std::string     description;                    ///< Description of the test.
+  std::string     text;                           ///< Input text.
+  unsigned int    numberOfTests;                  ///< The number of tests.
+  CharacterIndex* logicalIndex;                   ///< The logical cursor index for each test.
+  float*          heights;                        ///< The expected primary cursor height for each test.
+};
+
 bool GetClosestLineTest( const GetClosestLineData& data )
 {
   std::cout << "  testing : " << data.description << std::endl;
@@ -114,7 +125,8 @@ bool GetClosestLineTest( const GetClosestLineData& data )
                    false,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -163,7 +175,8 @@ bool GetClosestCursorIndexTest( const GetClosestCursorIndexData& data )
                    false,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -216,7 +229,8 @@ bool GetCursorPositionTest( const GetCursorPositionData& data )
                    false,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -233,6 +247,7 @@ bool GetCursorPositionTest( const GetCursorPositionData& data )
     parameters.logical = data.logicalIndex[index];
 
     GetCursorPosition( parameters,
+                       0.f,// Since this test case is not testing the primary cursor height, the default font line height can be set to 0.f.
                        cursorInfo );
 
     if( floor(cursorInfo.primaryPosition.x) != data.visualX[index] )
@@ -243,7 +258,7 @@ bool GetCursorPositionTest( const GetCursorPositionData& data )
     if( floor(cursorInfo.primaryPosition.y) != data.visualY[index] )
     {
       std::cout << "  test " << index << " failed. Different 'y' cursor position : " << cursorInfo.primaryPosition.y << ", expected : " << data.visualY[index] << std::endl;
-       return false;
+      return false;
     }
   }
 
@@ -272,7 +287,8 @@ bool FindSelectionIndicesTest( const FindSelectionIndicesData& data )
                    false,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -315,12 +331,102 @@ bool FindSelectionIndicesTest( const FindSelectionIndicesData& data )
   return true;
 }
 
+bool PrimaryCursorHeightTest( const PrimaryCursorHeightData& data )
+{
+  std::cout << "  testing : " << data.description << std::endl;
+
+  // 1) Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size textArea(400.f, 600.f);
+  Size layoutSize;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+
+  const std::string fontFamily( "DejaVuSans" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun1;
+  fontDescriptionRun1.characterRun.characterIndex = 0u;
+  fontDescriptionRun1.characterRun.numberOfCharacters = 13u;
+  fontDescriptionRun1.familyLength = fontFamily.size();
+  fontDescriptionRun1.familyName = new char[fontDescriptionRun1.familyLength];
+  memcpy( fontDescriptionRun1.familyName, fontFamily.c_str(), fontDescriptionRun1.familyLength );
+  fontDescriptionRun1.familyDefined = true;
+  fontDescriptionRun1.weightDefined = false;
+  fontDescriptionRun1.widthDefined = false;
+  fontDescriptionRun1.slantDefined = false;
+  fontDescriptionRun1.sizeDefined = true;
+  fontDescriptionRun1.size = 768u;//Font size = 12.0f (768/64 = 12)
+
+  fontDescriptionRuns.PushBack( fontDescriptionRun1 );
+
+  LayoutOptions options;
+  CreateTextModel( data.text,
+                   textArea,
+                   fontDescriptionRuns,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false,
+                   LineWrap::WORD,
+                   false,
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   50.f );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  GetCursorPositionParameters parameters;
+  parameters.visualModel = visualModel;
+  parameters.logicalModel = logicalModel;
+  parameters.metrics = metrics;
+  parameters.isMultiline = true;
+
+  for( unsigned int index = 0; index < data.numberOfTests; ++index )
+  {
+    CursorInfo cursorInfo;
+    parameters.logical = data.logicalIndex[index];
+
+    // 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 );
+
+    FontId fontID = fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSans.ttf" );
+
+    Text::FontMetrics fontMetrics;
+    MetricsPtr mMetrics = Metrics::New(fontClient);
+    mMetrics->GetFontMetrics(fontID, fontMetrics);
+    float defaultFontLineHeight = (fontMetrics.ascender - fontMetrics.descender);
+
+    GetCursorPosition( parameters,
+                       defaultFontLineHeight,
+                       cursorInfo );
+
+    if( floor(cursorInfo.primaryCursorHeight) != data.heights[index] )
+    {
+      std::cout << "  test " << index << " failed. Different primaryCursorHeight : " << cursorInfo.primaryCursorHeight << ", expected : " << data.heights[index] << std::endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
 } // namespace
 
 //////////////////////////////////////////////////////////
 //
 // UtcDaliGetClosestLine
 // UtcDaliGetClosestCursorIndex
+// UtcDaliGetCursorPosition
+// UtcDaliFindSelectionIndices
+// UtcDaliPrimaryCursorHeight
 //
 //////////////////////////////////////////////////////////
 
@@ -805,3 +911,35 @@ int UtcDaliFindSelectionIndices(void)
   tet_result(TET_PASS);
   END_TEST;
 }
+
+int UtcDaliPrimaryCursorHeight(void)
+{
+  tet_infoline(" UtcDaliPrimaryCursorHeight");
+
+  float heights[] = { 19.f };
+  CharacterIndex logicalIndex[] = { 1u };
+
+  struct PrimaryCursorHeightData data[] =
+  {
+    {
+      "Testing primary cursor height when line spacing is used.",
+      "Hello World",
+      1u,
+      logicalIndex,
+      heights,
+    }
+  };
+  const unsigned int numberOfTests = 1u;
+
+  for( unsigned int index = 0; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !PrimaryCursorHeightTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
index 402cc40..4f1d0f5 100755 (executable)
@@ -93,7 +93,8 @@ bool LayoutTextTest( const LayoutTextData& data )
                    false,
                    data.wrapMode,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   Vector<LineRun>& lines = textModel->mVisualModel->mLines;
 
index 281dbba..b50ab83 100755 (executable)
@@ -112,7 +112,8 @@ bool LayoutTextTest( const LayoutTextData& data )
                    false,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -370,7 +371,8 @@ bool AlignTest( const AlignData& data )
                    false,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
index 272db31..59a0dfd 100755 (executable)
@@ -144,7 +144,8 @@ bool ShapeInfoTest( const ShapeInfoData& data )
                    data.markupProcessorEnabled,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
index 2453771..a88a85d 100644 (file)
@@ -82,7 +82,8 @@ bool SetGlyphsPerCharacterTest( const SetGlyphsPerCharacterData& data )
                    false,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
@@ -169,7 +170,8 @@ bool SetCharacterToGlyphTest( const SetCharacterToGlyphData& data )
                    false,
                    LineWrap::WORD,
                    false,
-                   Toolkit::DevelText::EllipsisPosition::END );
+                   Toolkit::DevelText::EllipsisPosition::END,
+                   0.f );
 
   LogicalModelPtr logicalModel = textModel->mLogicalModel;
   VisualModelPtr visualModel = textModel->mVisualModel;
index 0bac46a..4e9890c 100644 (file)
@@ -4842,6 +4842,53 @@ int utcDaliTextEditorSelectionClearedSignal(void)
   END_TEST;
 }
 
+int utcDaliTextEditorSelectionWithSecondaryCursor(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorSelectionWithSecondaryCursor");
+
+  // Checks if the actor is created.
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  application.GetScene().Add( editor );
+
+  editor.SetProperty( TextEditor::Property::ENABLE_MARKUP, true );
+  editor.SetProperty( TextEditor::Property::TEXT, "اللغة العربية\nمرحبا بالجميع\nالسلام عليكم <span font-size='12' font-family='DejaVu Sans' >Hello world</span>" );
+  editor.SetProperty( TextEditor::Property::POINT_SIZE, 12.f );
+  editor.SetProperty( Actor::Property::SIZE, Vector2( 100.f, 50.f ) );
+  editor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
+  editor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
+  editor.SetProperty( DevelTextEditor::Property::MIN_LINE_SIZE, 50.f );
+  editor.SetProperty( DevelTextEditor::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION, false );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Tap on the text editor
+  TestGenerateTap( application, 3.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  //Select the last Arabic word (RTL) & some the space before the English (LTR) letters.
+  DevelTextEditor::SelectText( editor, 35, 41 );// This will activate the alternative cursor position and thus 'cursorInfo.isSecondaryCursor' will be true.
+
+  application.SendNotification();
+  application.Render();
+
+  std::string selectedText = editor.GetProperty( DevelTextEditor::Property::SELECTED_TEXT ).Get<std::string>();
+  DALI_TEST_EQUALS( "عليكم ", selectedText, TEST_LOCATION );
+
+  END_TEST;
+}
+
 int utcDaliTextEditorSelectionChangedSignal(void)
 {
   ToolkitTestApplication application;
index c2d35d9..7b08c47 100644 (file)
@@ -458,6 +458,7 @@ CharacterIndex GetClosestCursorIndex(VisualModelPtr         visualModel,
 }
 
 void GetCursorPosition(GetCursorPositionParameters& parameters,
+                       float                        defaultFontLineHeight,
                        CursorInfo&                  cursorInfo)
 {
   const LineRun* const modelLines = parameters.visualModel->mLines.Begin();
@@ -479,6 +480,15 @@ void GetCursorPosition(GetCursorPositionParameters& parameters,
   const LineIndex lineIndex = parameters.visualModel->GetLineOfCharacter(characterOfLine);
   const LineRun&  line      = *(modelLines + lineIndex);
 
+  const GlyphIndex* const charactersToGlyphBuffer  = parameters.visualModel->mCharactersToGlyph.Begin();
+  const Length* const     glyphsPerCharacterBuffer = parameters.visualModel->mGlyphsPerCharacter.Begin();
+  const GlyphInfo* const  glyphInfoBuffer          = parameters.visualModel->mGlyphs.Begin();
+  CharacterIndex          index;
+  GlyphMetrics            glyphMetrics;
+  MetricsPtr&             metrics = parameters.metrics;
+  GlyphIndex glyphIndex = 0u;
+  Length numberOfGlyphs = 0u;
+
   if(isLastNewParagraph)
   {
     // The cursor is in a new line with no characters. Place the cursor in that line.
@@ -493,8 +503,14 @@ void GetCursorPosition(GetCursorPositionParameters& parameters,
 
     cursorInfo.lineHeight = GetLineHeight(newLine);
 
+    const Length totalNumberOfCharacters = parameters.logicalModel->mText.Count();
+    index                                = totalNumberOfCharacters - 1;
+
+    GetGlyphMetricsFromCharacterIndex(index, glyphInfoBuffer, charactersToGlyphBuffer, glyphsPerCharacterBuffer, metrics, glyphMetrics, glyphIndex, numberOfGlyphs);
+
     // Set the primary cursor's height.
-    cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
+    // The primary cursor height will take the font height of the last character and if there are no characters, it'll take the default font line height.
+    cursorInfo.primaryCursorHeight = (totalNumberOfCharacters > 0) ? (cursorInfo.isSecondaryCursor ? 0.5f * glyphMetrics.fontHeight : glyphMetrics.fontHeight) : defaultFontLineHeight;
 
     // Set the primary cursor's position.
     cursorInfo.primaryPosition.x = (LTR == line.direction) ? newLine.alignmentOffset : parameters.visualModel->mControlSize.width - newLine.alignmentOffset;
@@ -541,7 +557,7 @@ void GetCursorPosition(GetCursorPositionParameters& parameters,
 
     // Calculate the primary cursor.
 
-    CharacterIndex index = characterIndex;
+    index = characterIndex;
     if(cursorInfo.isSecondaryCursor)
     {
       // If there is a secondary position, the primary cursor may be in a different place than the logical index.
@@ -574,26 +590,14 @@ void GetCursorPosition(GetCursorPositionParameters& parameters,
       }
     }
 
-    const GlyphIndex* const     charactersToGlyphBuffer  = parameters.visualModel->mCharactersToGlyph.Begin();
-    const Length* const         glyphsPerCharacterBuffer = parameters.visualModel->mGlyphsPerCharacter.Begin();
     const Length* const         charactersPerGlyphBuffer = parameters.visualModel->mCharactersPerGlyph.Begin();
     const CharacterIndex* const glyphsToCharactersBuffer = parameters.visualModel->mGlyphsToCharacters.Begin();
     const Vector2* const        glyphPositionsBuffer     = parameters.visualModel->mGlyphPositions.Begin();
-    const GlyphInfo* const      glyphInfoBuffer          = parameters.visualModel->mGlyphs.Begin();
 
-    // Convert the cursor position into the glyph position.
-    const GlyphIndex primaryGlyphIndex         = *(charactersToGlyphBuffer + index);
-    const Length     primaryNumberOfGlyphs     = *(glyphsPerCharacterBuffer + index);
+    GetGlyphMetricsFromCharacterIndex(index, glyphInfoBuffer, charactersToGlyphBuffer, glyphsPerCharacterBuffer, metrics, glyphMetrics, glyphIndex, numberOfGlyphs);
+    const GlyphIndex primaryGlyphIndex         = glyphIndex;
     const Length     primaryNumberOfCharacters = *(charactersPerGlyphBuffer + primaryGlyphIndex);
 
-    // Get the metrics for the group of glyphs.
-    GlyphMetrics glyphMetrics;
-    GetGlyphsMetrics(primaryGlyphIndex,
-                     primaryNumberOfGlyphs,
-                     glyphMetrics,
-                     glyphInfoBuffer,
-                     parameters.metrics);
-
     // Whether to add the glyph's advance to the cursor position.
     // i.e if the paragraph is left to right and the logical cursor is zero, the position is the position of the first glyph and the advance is not added,
     //     if the logical cursor is one, the position is the position of the first glyph and the advance is added.
@@ -676,16 +680,9 @@ void GetCursorPosition(GetCursorPositionParameters& parameters,
         index = (isRightToLeftParagraph == isCurrentRightToLeft) ? nextCharacterIndex : characterIndex;
       }
 
-      const GlyphIndex secondaryGlyphIndex     = *(charactersToGlyphBuffer + index);
-      const Length     secondaryNumberOfGlyphs = *(glyphsPerCharacterBuffer + index);
-
-      const Vector2& secondaryPosition = *(glyphPositionsBuffer + secondaryGlyphIndex);
-
-      GetGlyphsMetrics(secondaryGlyphIndex,
-                       secondaryNumberOfGlyphs,
-                       glyphMetrics,
-                       glyphInfoBuffer,
-                       parameters.metrics);
+      GetGlyphMetricsFromCharacterIndex(index, glyphInfoBuffer, charactersToGlyphBuffer, glyphsPerCharacterBuffer, metrics, glyphMetrics, glyphIndex, numberOfGlyphs);
+      const GlyphIndex secondaryGlyphIndex = glyphIndex;
+      const Vector2&   secondaryPosition   = *(glyphPositionsBuffer + secondaryGlyphIndex);
 
       // Set the secondary cursor's position.
 
index dc005a3..4414743 100644 (file)
@@ -22,6 +22,7 @@
 #include <dali-toolkit/internal/text/logical-model-impl.h>
 #include <dali-toolkit/internal/text/metrics.h>
 #include <dali-toolkit/internal/text/visual-model-impl.h>
+#include <dali-toolkit/internal/text/glyph-metrics-helper.h>
 
 namespace Dali
 {
@@ -142,9 +143,11 @@ CharacterIndex GetClosestCursorIndex(VisualModelPtr         visualModel,
  * if there is a valid alternative cursor, its position and height.
  *
  * @param[in] parameters Parameters used to calculate the cursor's position.
+ * @param[in] defaultFontLineHeight The default font line height.
  * @param[out] cursorInfo The line's height, the cursor's height, the cursor's position and whether there is an alternative cursor.
  */
 void GetCursorPosition(GetCursorPositionParameters& parameters,
+                       float                        defaultFontLineHeight,
                        CursorInfo&                  cursorInfo);
 
 /**
index 1f27a84..f87555e 100644 (file)
@@ -100,6 +100,20 @@ void GetGlyphsMetrics(GlyphIndex             glyphIndex,
   glyphMetrics.width += (firstGlyph.isItalicRequired && !isItalicFont) ? TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE * firstGlyph.height : 0.f;
 }
 
+void GetGlyphMetricsFromCharacterIndex(CharacterIndex index, const GlyphInfo* const glyphInfoBuffer, const GlyphIndex* const charactersToGlyphBuffer, const Length* const glyphsPerCharacterBuffer, MetricsPtr& metrics, GlyphMetrics& glyphMetrics, GlyphIndex& glyphIndex, Length& numberOfGlyphs)
+{
+  //Takes the character index, obtains the glyph index (and the number of Glyphs) from it and finally gets the glyph metrics.
+  glyphIndex     = *(charactersToGlyphBuffer + index);
+  numberOfGlyphs = *(glyphsPerCharacterBuffer + index);
+
+  // Get the metrics for the group of glyphs.
+  GetGlyphsMetrics(glyphIndex,
+                   numberOfGlyphs,
+                   glyphMetrics,
+                   glyphInfoBuffer,
+                   metrics);
+}
+
 } // namespace Text
 
 } // namespace Toolkit
index 05ba882..dac57f0 100644 (file)
@@ -83,6 +83,28 @@ void GetGlyphsMetrics(GlyphIndex             glyphIndex,
                       const GlyphInfo* const glyphsBuffer,
                       MetricsPtr&            metrics);
 
+/**
+ * @brief Takes the character index, obtains the glyph index (and the number of Glyphs) from it and finally gets the glyph metrics.
+ *
+ * @param[in] index The character index.
+ * @param[in] glyphInfoBuffer The glyphs buffer.
+ * @param[in] charactersToGlyphBuffer A vector containing the glyph index for each character.
+ * @param[in] glyphsPerCharacterBuffer A vector containing the number of glyphs in each character.
+ * @param[in] metrics Used to access metrics from FontClient.
+ * @param[out] glyphMetrics Some glyph metrics (font height, advance, ascender and x bearing).
+ * @param[out] glyphIndex The glyph index obtained from the character index.
+ * @param[out] numberOfGlyphs The number of glyphs in the character of which the index was passed to the function.
+ *
+ */
+void GetGlyphMetricsFromCharacterIndex(CharacterIndex          index,
+                                       const GlyphInfo* const  glyphInfoBuffer,
+                                       const GlyphIndex* const charactersToGlyphBuffer,
+                                       const Length* const     glyphsPerCharacterBuffer,
+                                       MetricsPtr&             metrics,
+                                       GlyphMetrics&           glyphMetrics,
+                                       GlyphIndex&             glyphIndex,
+                                       Length&                 numberOfGlyphs);
+
 } // namespace Text
 
 } // namespace Toolkit
index f287daf..e0603f8 100644 (file)
@@ -1195,7 +1195,10 @@ void Controller::Impl::GetCursorPosition(CharacterIndex logical,
   parameters.logical      = logical;
   parameters.isMultiline  = isMultiLine;
 
+  float defaultFontLineHeight = GetDefaultFontLineHeight();
+
   Text::GetCursorPosition(parameters,
+                          defaultFontLineHeight,
                           cursorInfo);
 
   // Adds Outline offset.