TextController - Update the text model. 57/65557/11
authorVictor Cebollada <v.cebollada@samsung.com>
Mon, 21 Mar 2016 10:18:33 +0000 (10:18 +0000)
committerVíctor Cebollada <v.cebollada@samsung.com>
Thu, 21 Apr 2016 10:28:33 +0000 (03:28 -0700)
* Updates the paragraphs that are being edited instead creating the whole text model from scratch.

Change-Id: I19c3b841a264a75c97a39ebcc64a5685604eb9c8
Signed-off-by: Victor Cebollada <v.cebollada@samsung.com>
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Layout.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-VisualModel.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.cpp
dali-toolkit/internal/text/layouts/layout-engine.cpp
dali-toolkit/internal/text/layouts/layout-parameters.h
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/internal/text/text-controller-impl.h
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-controller.h
dali-toolkit/internal/text/text-view.cpp

index d849430..521cbf9 100644 (file)
@@ -177,6 +177,7 @@ bool LayoutTextTest( const LayoutTextData& data )
   layoutParameters.startGlyphIndex = data.startIndex;
   layoutParameters.numberOfGlyphs = data.numberOfGlyphs;
   layoutParameters.startLineIndex = startRemoveIndex;
+  layoutParameters.estimatedNumberOfLines = logicalModel->mParagraphInfo.Count();
 
   layoutSize = Vector2::ZERO;
 
@@ -746,7 +747,7 @@ int UtcDaliTextLayoutSmallTextArea02(void)
   fontDescriptionRuns.PushBack( fontDescriptionRun );
   Size textArea(1.f, 1.f);
   Size layoutSize(80.f, 20.f);
-  float positions[] = { 1.f, 3.f, 12.f, 6.f, 20.f, 2.f, 24.f, 2.f, 27.f, 6.f, 36.f, 15.f, 40.f, 6.f, 51.f, 6.f, 61.f, 6.f, 67.f, 2.f, 70.f, 2.f };
+  float positions[] = { 1.f, -12.f, 12.f, -9.f, 20.f, -13.f, 24.f, -13.f, 27.f, -9.f, 36.f, -0.f, 40.f, -9.f, 51.f, -9.f, 61.f, -9.f, 67.f, -13.f, 70.f, -13.f };
   struct LineRun line =
   {
     { 0u, 11u },
@@ -831,11 +832,11 @@ int UtcDaliTextLayoutMultilineText01(void)
   Size layoutSize(95.f, 97.f);
   float positions[] =
   {
-    1.f, 3.f, 12.f, 6.f, 20.f, 2.f, 24.f, 2.f, 27.f, 6.f, 36.f, 15.f, 40.f, 6.f, 51.f, 6.f, 61.f, 6.f, 67.f, 2.f, 70.f, 2.f, 79.f, 15.f,
-    0.f, 22.f, 10.f, 26.f, 18.f, 26.f, 30.f, 26.f, 39.f, 32.f, 42.f, 23.f,
-    1.f, 43.f, 9.f, 46.f, 17.f, 46.f, 27.f, 46.f, 36.f, 46.f, 45.f, 44.f, 51.f, 55.f,
-    1.f, 62.f, 11.f, 62.f, 15.f, 62.f, 26.f, 65.f, 35.f, 65.f, 41.f, 65.f, 50.f, 65.f, 59.f, 63.f, 65.f, 74.f,
-    1.f, 81.f, 5.f, 81.f, 9.f, 84.f, 19.f, 84.f, 28.f, 84.f, 35.f, 93.f, 41.f, 84.f, 50.f, 81.f, 54.f, 93.f, 59.f, 82.f, 66.f, 84.f, 75.f, 84.f, 83.f, 82.f, 91.f, 91.f
+    1.f, -12.f, 12.f,  -9.f, 20.f, -13.f, 24.f, -13.f, 27.f, -9.f, 36.f,  -0.f, 40.f, -9.f, 51.f,  -9.f, 61.f, -9.f, 67.f, -13.f, 70.f, -13.f, 79.f, -0.f,
+    0.f, -13.f, 10.f,  -9.f, 18.f,  -9.f, 30.f,  -9.f, 39.f, -3.f, 42.f, -12.f,
+    1.f, -12.f,  9.f,  -9.f, 17.f,  -9.f, 27.f,  -9.f, 36.f, -9.f, 45.f, -11.f, 51.f, -0.f,
+    1.f, -12.f, 11.f, -12.f, 15.f, -12.f, 26.f,  -9.f, 35.f, -9.f, 41.f,  -9.f, 50.f, -9.f, 59.f, -11.f, 65.f, -0.f,
+    1.f, -12.f,  5.f, -12.f,  9.f,  -9.f, 19.f,  -9.f, 28.f, -9.f, 35.f,  -0.f, 41.f, -9.f, 50.f, -12.f, 54.f, -0.f, 59.f, -11.f, 66.f,  -9.f, 75.f, -9.f, 83.f, -11.f, 91.f, -2.f
   };
   struct LineRun line0 =
   {
@@ -1009,12 +1010,12 @@ int UtcDaliTextLayoutMultilineText02(void)
   Size layoutSize(81.f, 120.f);
   float positions[] =
   {
-    1.f, 3.f, 12.f, 6.f, 20.f, 2.f, 24.f, 2.f, 27.f, 6.f, 36.f, 15.f, 40.f, 6.f, 51.f, 6.f, 61.f, 6.f, 67.f, 2.f, 70.f, 2.f, 79.f, 15.f,
-    0.f, 22.f, 10.f, 26.f, 18.f, 26.f, 30.f, 26.f, 39.f, 35.f, 44.f, 25.f, 55.f, 22.f, 62.f, 25.f, 67.f, 25.f, 75.f, 35.f,
-    1.f, 45.f, 9.f, 45.f, 14.f, 42.f, 22.f, 45.f, 32.f, 53.f, 35.f, 44.f,
-    1.f, 65.f, 12.f, 62.f, 19.f, 65.f, 24.f, 65.f, 32.f, 75.f, 37.f, 65.f, 45.f, 65.f, 50.f, 62.f, 58.f, 65.f, 66.f, 75.f,
-    1.f, 82.f, 10.f, 86.f, 18.f, 82.f, 22.f, 82.f, 25.f, 86.f, 34.f, 95.f, 38.f, 86.f, 49.f, 86.f, 59.f, 86.f, 65.f, 82.f, 68.f, 82.f, 77.f, 95.f,
-    0.f, 102.f, 10.f, 106.f, 18.f, 106.f, 30.f, 106.f, 39.f, 112.f
+    1.f, -12.f, 12.f,  -9.f, 20.f, -13.f, 24.f, -13.f, 27.f, -9.f, 36.f,  -0.f, 40.f,  -9.f, 51.f,  -9.f, 61.f,  -9.f, 67.f, -13.f, 70.f, -13.f, 79.f, -0.f,
+    0.f, -13.f, 10.f,  -9.f, 18.f,  -9.f, 30.f,  -9.f, 39.f, -0.f, 44.f, -10.f, 55.f, -13.f, 62.f, -10.f, 67.f, -10.f, 75.f,  -0.f,
+    1.f, -10.f,  9.f, -10.f, 14.f, -13.f, 22.f, -10.f, 32.f, -2.f, 35.f, -11.f,
+    1.f, -10.f, 12.f, -13.f, 19.f, -10.f, 24.f, -10.f, 32.f, -0.f, 37.f, -10.f, 45.f, -10.f, 50.f, -13.f, 58.f, -10.f, 66.f,  -0.f,
+    1.f, -13.f, 10.f,  -9.f, 18.f, -13.f, 22.f, -13.f, 25.f, -9.f, 34.f,  -0.f, 38.f,  -9.f, 49.f,  -9.f, 59.f,  -9.f, 65.f, -13.f, 68.f, -13.f, 77.f, -0.f,
+    0.f, -13.f, 10.f,  -9.f, 18.f,  -9.f, 30.f,  -9.f, 39.f, -3.f,
   };
   struct LineRun line0 =
   {
@@ -1153,9 +1154,9 @@ int UtcDaliTextLayoutMultilineText03(void)
   Size layoutSize(96.f, 60.f);
   float positions[] =
   {
-    1.f, 3.f, 12.f, 6.f, 20.f, 2.f, 24.f, 2.f, 27.f, 6.f, 36.f, 6.f, 47.f, 6.f, 57.f, 6.f, 63.f, 2.f, 66.f, 2.f, 75.f, 2.f, 85.f, 6.f,
-    1.f, 26.f, 13.f, 26.f, 23.f, 22.f, 32.f, 26.f, 40.f, 22.f, 44.f, 22.f, 47.f, 26.f, 56.f, 26.f, 67.f, 26.f, 77.f, 26.f, 83.f, 22.f, 86.f, 22.f,
-    0.f, 42.f, 10.f, 46.f, 18.f, 46.f, 30.f, 46.f, 39.f, 52.f
+    1.f, -12.f, 12.f, -9.f, 20.f, -13.f, 24.f, -13.f, 27.f,  -9.f, 36.f,  -9.f, 47.f, -9.f, 57.f, -9.f, 63.f, -13.f, 66.f, -13.f, 75.f, -13.f, 85.f,  -9.f,
+    1.f,  -9.f, 13.f, -9.f, 23.f, -13.f, 32.f,  -9.f, 40.f, -13.f, 44.f, -13.f, 47.f, -9.f, 56.f, -9.f, 67.f,  -9.f, 77.f,  -9.f, 83.f, -13.f, 86.f, -13.f,
+    0.f, -13.f, 10.f, -9.f, 18.f,  -9.f, 30.f,  -9.f, 39.f,  -3.f,
   };
   struct LineRun line0 =
   {
@@ -1254,7 +1255,7 @@ int UtcDaliTextLayoutMultilineText04(void)
   Size layoutSize(83.f, 40.f);
   float positions[] =
   {
-    1.f, 3.f, 12.f, 6.f, 20.f, 2.f, 24.f, 2.f, 27.f, 6.f, 36.f, 15.f, 40.f, 6.f, 51.f, 6.f, 61.f, 6.f, 67.f, 2.f, 70.f, 2.f, 79.f, 12.f, 82.f, 3.f
+    1.f, -12.f, 12.f, -9.f, 20.f, -13.f, 24.f, -13.f, 27.f, -9.f, 36.f, -0.f, 40.f, -9.f, 51.f, -9.f, 61.f, -9.f, 67.f, -13.f, 70.f, -13.f, 79.f, -3.f, 82.f, -12.f
   };
   struct LineRun line0 =
   {
@@ -1367,8 +1368,8 @@ int UtcDaliTextLayoutMultilineText05(void)
   Size layoutSize(88.f, 53.f);
   float positions[] =
   {
-    1.f, 13.f, 12.f, 16.f, 20.f, 12.f, 24.f, 12.f, 27.f, 16.f, 36.f, 25.f, 40.f, 11.f, 59.f, 16.f, 69.f, 16.f, 75.f, 12.f, 78.f, 12.f, 87.f, 25.f,
-    0.f, 35.f, 10.f, 39.f, 18.f, 39.f, 30.f, 39.f, 39.f, 45.f
+    1.f, -12.f, 12.f, -9.f, 20.f, -13.f, 24.f, -13.f, 27.f, -9.f, 36.f, -0.f, 40.f, -14.f, 59.f, -9.f, 69.f, -9.f, 75.f, -13.f, 78.f, -13.f, 87.f, -0.f,
+    0.f, -13.f, 10.f, -9.f, 18.f,  -9.f, 30.f,  -9.f, 39.f, -3.f
   };
   struct LineRun line0 =
   {
@@ -1652,24 +1653,24 @@ int UtcDaliTextUpdateLayout01(void)
   Size layoutSize(92.f, 380.f);
   float positions[] =
   {
-    1.f, 3.f, 12.f, 6.f, 20.f, 2.f, 24.f, 2.f, 27.f, 6.f, 36.f, 15.f, 40.f, 6.f, 51.f, 6.f, 61.f, 6.f, 67.f, 2.f, 70.f, 2.f, 79.f, 15.f,
-    0.f, 22.f, 10.f, 26.f, 18.f, 26.f, 30.f, 26.f, 39.f, 35.f, 44.f, 25.f, 55.f, 22.f, 62.f, 25.f, 67.f, 25.f, 75.f, 35.f,
-    1.f, 45.f, 9.f, 45.f, 14.f, 42.f, 22.f, 45.f, 32.f, 53.f, 35.f, 44.f,
-    0.f, 67.f, 7.f, 69.f, 12.f, 68.f, 18.f, 68.f, 23.f, 64.f, 25.f, 75.f, 27.f, 68.f, 32.f, 64.f, 33.f, 64.f, 37.f, 67.f, 44.f, 64.f, 45.f, 64.f, 49.f, 67.f, 55.f, 75.f, 59.f, 62.f, 68.f, 66.f, 76.f, 62.f, 80.f, 62.f, 83.f, 66.f, 92.f, 75.f,
-    0.f, 86.f, 11.f, 86.f, 21.f, 86.f, 27.f, 82.f, 30.f, 82.f, 39.f, 95.f, 44.f, 85.f, 55.f, 82.f, 62.f, 85.f, 67.f, 85.f, 75.f, 95.f,
-    1.f, 105.f, 9.f, 105.f, 14.f, 102.f, 22.f, 105.f, 30.f, 115.f,
-    1.f, 125.f, 12.f, 122.f, 19.f, 125.f, 24.f, 125.f, 32.f, 135.f, 37.f, 125.f, 45.f, 125.f, 50.f, 122.f, 58.f, 125.f, 66.f, 135.f,
-    1.f, 142.f, 10.f, 146.f, 18.f, 142.f, 22.f, 142.f, 25.f, 146.f, 34.f, 155.f, 38.f, 146.f, 49.f, 146.f, 59.f, 146.f, 65.f, 142.f, 68.f, 142.f, 77.f, 155.f,
-    0.f, 162.f, 10.f, 166.f, 18.f, 166.f, 30.f, 166.f, 39.f, 172.f, 42.f, 163.f,
-    1.f, 182.f, 10.f, 186.f, 18.f, 182.f, 22.f, 182.f, 25.f, 186.f, 34.f, 195.f, 38.f, 186.f, 49.f, 186.f, 59.f, 186.f, 65.f, 182.f, 68.f, 182.f, 77.f, 195.f,
-    0.f, 207.f, 7.f, 209.f, 12.f, 208.f, 18.f, 208.f, 23.f, 204.f, 25.f, 215.f, 27.f, 208.f, 32.f, 204.f, 33.f, 204.f, 37.f, 207.f, 44.f, 204.f, 45.f, 204.f, 49.f, 207.f, 55.f, 215.f, 59.f, 205.f, 70.f, 202.f, 77.f, 205.f, 82.f, 205.f, 90.f, 215.f,
-    1.f, 225.f, 9.f, 225.f, 14.f, 222.f, 22.f, 225.f, 30.f, 235.f,
-    1.f, 243.f, 12.f, 246.f, 20.f, 242.f, 24.f, 242.f, 27.f, 246.f, 36.f, 255.f, 40.f, 246.f, 51.f, 246.f, 61.f, 246.f, 67.f, 242.f, 70.f, 242.f, 79.f, 255.f,
-    0.f, 262.f, 10.f, 266.f, 18.f, 266.f, 30.f, 266.f, 39.f, 275.f, 44.f, 265.f, 55.f, 262.f, 62.f, 265.f, 67.f, 265.f, 75.f, 275.f,
-    1.f, 285.f, 9.f, 285.f, 14.f, 282.f, 22.f, 285.f, 32.f, 293.f, 35.f, 284.f,
-    1.f, 305.f, 12.f, 302.f, 19.f, 305.f, 24.f, 305.f, 32.f, 315.f, 37.f, 305.f, 45.f, 305.f, 50.f, 302.f, 58.f, 305.f, 66.f, 315.f,
-    1.f, 322.f, 10.f, 326.f, 18.f, 322.f, 22.f, 322.f, 25.f, 326.f, 34.f, 335.f, 38.f, 326.f, 49.f, 326.f, 59.f, 326.f, 65.f, 322.f, 68.f, 322.f, 77.f, 335.f,
-    0.f, 347.f, 7.f, 349.f, 12.f, 348.f, 18.f, 348.f, 23.f, 344.f, 25.f, 355.f, 27.f, 348.f, 32.f, 344.f, 33.f, 344.f, 37.f, 347.f, 44.f, 344.f, 45.f, 344.f, 49.f, 347.f, 55.f, 355.f,
+    1.f, -12.f, 12.f, -9.f, 20.f, -13.f, 24.f, -13.f, 27.f, -9.f, 36.f, -0.f, 40.f, -9.f, 51.f, -9.f, 61.f, -9.f, 67.f, -13.f, 70.f, -13.f, 79.f, -0.f,
+    0.f, -13.f, 10.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -0.f, 44.f, -10.f, 55.f, -13.f, 62.f, -10.f, 67.f, -10.f, 75.f, -0.f,
+    1.f, -10.f, 9.f, -10.f, 14.f, -13.f, 22.f, -10.f, 32.f, -2.f, 35.f, -11.f,
+    0.f, -8.f, 7.f, -6.f, 12.f, -7.f, 18.f, -7.f, 23.f, -11.f, 25.f, -0.f, 27.f, -7.f, 32.f, -11.f, 33.f, -11.f, 37.f, -8.f, 44.f, -11.f, 45.f, -11.f, 49.f, -8.f, 55.f, -0.f, 59.f, -13.f, 68.f, -9.f, 76.f, -13.f, 80.f, -13.f, 83.f, -9.f, 92.f, -0.f,
+    0.f, -9.f, 11.f, -9.f, 21.f, -9.f, 27.f, -13.f, 30.f, -13.f, 39.f, -0.f, 44.f, -10.f, 55.f, -13.f, 62.f, -10.f, 67.f, -10.f, 75.f, -0.f,
+    1.f, -10.f, 9.f, -10.f, 14.f, -13.f, 22.f, -10.f, 30.f, -0.f,
+    1.f, -10.f, 12.f, -13.f, 19.f, -10.f, 24.f, -10.f, 32.f, -0.f, 37.f, -10.f, 45.f, -10.f, 50.f, -13.f, 58.f, -10.f, 66.f, -0.f,
+    1.f, -13.f, 10.f, -9.f, 18.f, -13.f, 22.f, -13.f, 25.f, -9.f, 34.f, -0.f, 38.f, -9.f, 49.f, -9.f, 59.f, -9.f, 65.f, -13.f, 68.f, -13.f, 77.f, -0.f,
+    0.f, -13.f, 10.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -3.f, 42.f, -12.f,
+    1.f, -13.f, 10.f, -9.f, 18.f, -13.f, 22.f, -13.f, 25.f, -9.f, 34.f, -0.f, 38.f, -9.f, 49.f, -9.f, 59.f, -9.f, 65.f, -13.f, 68.f, -13.f, 77.f, -0.f,
+    0.f, -8.f, 7.f, -6.f, 12.f, -7.f, 18.f, -7.f, 23.f, -11.f, 25.f, -0.f, 27.f, -7.f, 32.f, -11.f, 33.f, -11.f, 37.f, -8.f, 44.f, -11.f, 45.f, -11.f, 49.f, -8.f, 55.f, -0.f, 59.f, -10.f, 70.f, -13.f, 77.f, -10.f, 82.f, -10.f, 90.f, -0.f,
+    1.f, -10.f, 9.f, -10.f, 14.f, -13.f, 22.f, -10.f, 30.f, -0.f,
+    1.f, -12.f, 12.f, -9.f, 20.f, -13.f, 24.f, -13.f, 27.f, -9.f, 36.f, -0.f, 40.f, -9.f, 51.f, -9.f, 61.f, -9.f, 67.f, -13.f, 70.f, -13.f, 79.f, -0.f,
+    0.f, -13.f, 10.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -0.f, 44.f, -10.f, 55.f, -13.f, 62.f, -10.f, 67.f, -10.f, 75.f, -0.f,
+    1.f, -10.f, 9.f, -10.f, 14.f, -13.f, 22.f, -10.f, 32.f, -2.f, 35.f, -11.f,
+    1.f, -10.f, 12.f, -13.f, 19.f, -10.f, 24.f, -10.f, 32.f, -0.f, 37.f, -10.f, 45.f, -10.f, 50.f, -13.f, 58.f, -10.f, 66.f, -0.f,
+    1.f, -13.f, 10.f, -9.f, 18.f, -13.f, 22.f, -13.f, 25.f, -9.f, 34.f, -0.f, 38.f, -9.f, 49.f, -9.f, 59.f, -9.f, 65.f, -13.f, 68.f, -13.f, 77.f, -0.f,
+    0.f, -8.f, 7.f, -6.f, 12.f, -7.f, 18.f, -7.f, 23.f, -11.f, 25.f, -0.f, 27.f, -7.f, 32.f, -11.f, 33.f, -11.f, 37.f, -8.f, 44.f, -11.f, 45.f, -11.f, 49.f, -8.f, 55.f, -0.f,
   };
   struct LineRun line01 =
   {
@@ -2179,24 +2180,24 @@ int UtcDaliTextUpdateLayout02(void)
   Size layoutSize(92.f, 380.f);
   float positions[] =
   {
-    1.f, 3.f, 12.f, 6.f, 20.f, 2.f, 24.f, 2.f, 27.f, 6.f, 36.f, 15.f, 40.f, 6.f, 51.f, 6.f, 61.f, 6.f, 67.f, 2.f, 70.f, 2.f, 79.f, 15.f,
-    0.f, 22.f, 10.f, 26.f, 18.f, 26.f, 30.f, 26.f, 39.f, 35.f, 44.f, 25.f, 55.f, 22.f, 62.f, 25.f, 67.f, 25.f, 75.f, 35.f,
-    1.f, 45.f, 9.f, 45.f, 14.f, 42.f, 22.f, 45.f, 32.f, 53.f, 35.f, 44.f,
-    0.f, 67.f, 7.f, 69.f, 12.f, 68.f, 18.f, 68.f, 23.f, 64.f, 25.f, 75.f, 27.f, 68.f, 32.f, 64.f, 33.f, 64.f, 37.f, 67.f, 44.f, 64.f, 45.f, 64.f, 49.f, 67.f, 55.f, 75.f, 59.f, 62.f, 68.f, 66.f, 76.f, 62.f, 80.f, 62.f, 83.f, 66.f, 92.f, 75.f,
-    0.f, 86.f, 11.f, 86.f, 21.f, 86.f, 27.f, 82.f, 30.f, 82.f, 39.f, 95.f, 44.f, 85.f, 55.f, 82.f, 62.f, 85.f, 67.f, 85.f, 75.f, 95.f,
-    1.f, 105.f, 9.f, 105.f, 14.f, 102.f, 22.f, 105.f, 30.f, 115.f,
-    1.f, 125.f, 12.f, 122.f, 19.f, 125.f, 24.f, 125.f, 32.f, 135.f, 37.f, 125.f, 45.f, 125.f, 50.f, 122.f, 58.f, 125.f, 66.f, 135.f,
-    1.f, 142.f, 10.f, 146.f, 18.f, 142.f, 22.f, 142.f, 25.f, 146.f, 34.f, 155.f, 38.f, 146.f, 49.f, 146.f, 59.f, 146.f, 65.f, 142.f, 68.f, 142.f, 77.f, 155.f,
-    0.f, 162.f, 10.f, 166.f, 18.f, 166.f, 30.f, 166.f, 39.f, 172.f, 42.f, 163.f,
-    1.f, 182.f, 10.f, 186.f, 18.f, 182.f, 22.f, 182.f, 25.f, 186.f, 34.f, 195.f, 38.f, 186.f, 49.f, 186.f, 59.f, 186.f, 65.f, 182.f, 68.f, 182.f, 77.f, 195.f,
-    0.f, 207.f, 7.f, 209.f, 12.f, 208.f, 18.f, 208.f, 23.f, 204.f, 25.f, 215.f, 27.f, 208.f, 32.f, 204.f, 33.f, 204.f, 37.f, 207.f, 44.f, 204.f, 45.f, 204.f, 49.f, 207.f, 55.f, 215.f, 59.f, 205.f, 70.f, 202.f, 77.f, 205.f, 82.f, 205.f, 90.f, 215.f,
-    1.f, 225.f, 9.f, 225.f, 14.f, 222.f, 22.f, 225.f, 30.f, 235.f,
-    1.f, 243.f, 12.f, 246.f, 20.f, 242.f, 24.f, 242.f, 27.f, 246.f, 36.f, 255.f, 40.f, 246.f, 51.f, 246.f, 61.f, 246.f, 67.f, 242.f, 70.f, 242.f, 79.f, 255.f,
-    0.f, 262.f, 10.f, 266.f, 18.f, 266.f, 30.f, 266.f, 39.f, 275.f, 44.f, 265.f, 55.f, 262.f, 62.f, 265.f, 67.f, 265.f, 75.f, 275.f,
-    1.f, 285.f, 9.f, 285.f, 14.f, 282.f, 22.f, 285.f, 32.f, 293.f, 35.f, 284.f,
-    1.f, 305.f, 12.f, 302.f, 19.f, 305.f, 24.f, 305.f, 32.f, 315.f, 37.f, 305.f, 45.f, 305.f, 50.f, 302.f, 58.f, 305.f, 66.f, 315.f,
-    1.f, 322.f, 10.f, 326.f, 18.f, 322.f, 22.f, 322.f, 25.f, 326.f, 34.f, 335.f, 38.f, 326.f, 49.f, 326.f, 59.f, 326.f, 65.f, 322.f, 68.f, 322.f, 77.f, 335.f,
-    0.f, 347.f, 7.f, 349.f, 12.f, 348.f, 18.f, 348.f, 23.f, 344.f, 25.f, 355.f, 27.f, 348.f, 32.f, 344.f, 33.f, 344.f, 37.f, 347.f, 44.f, 344.f, 45.f, 344.f, 49.f, 347.f, 55.f, 355.f,
+    1.f, -12.f, 12.f, -9.f, 20.f, -13.f, 24.f, -13.f, 27.f, -9.f, 36.f, -0.f, 40.f, -9.f, 51.f, -9.f, 61.f, -9.f, 67.f, -13.f, 70.f, -13.f, 79.f, -0.f,
+    0.f, -13.f, 10.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -0.f, 44.f, -10.f, 55.f, -13.f, 62.f, -10.f, 67.f, -10.f, 75.f, -0.f,
+    1.f, -10.f, 9.f, -10.f, 14.f, -13.f, 22.f, -10.f, 32.f, -2.f, 35.f, -11.f,
+    0.f, -8.f, 7.f, -6.f, 12.f, -7.f, 18.f, -7.f, 23.f, -11.f, 25.f, -0.f, 27.f, -7.f, 32.f, -11.f, 33.f, -11.f, 37.f, -8.f, 44.f, -11.f, 45.f, -11.f, 49.f, -8.f, 55.f, -0.f, 59.f, -13.f, 68.f, -9.f, 76.f, -13.f, 80.f, -13.f, 83.f, -9.f, 92.f, -0.f,
+    0.f, -9.f, 11.f, -9.f, 21.f, -9.f, 27.f, -13.f, 30.f, -13.f, 39.f, -0.f, 44.f, -10.f, 55.f, -13.f, 62.f, -10.f, 67.f, -10.f, 75.f, -0.f,
+    1.f, -10.f, 9.f, -10.f, 14.f, -13.f, 22.f, -10.f, 30.f, -0.f,
+    1.f, -10.f, 12.f, -13.f, 19.f, -10.f, 24.f, -10.f, 32.f, -0.f, 37.f, -10.f, 45.f, -10.f, 50.f, -13.f, 58.f, -10.f, 66.f, -0.f,
+    1.f, -13.f, 10.f, -9.f, 18.f, -13.f, 22.f, -13.f, 25.f, -9.f, 34.f, -0.f, 38.f, -9.f, 49.f, -9.f, 59.f, -9.f, 65.f, -13.f, 68.f, -13.f, 77.f, -0.f,
+    0.f, -13.f, 10.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -3.f, 42.f, -12.f,
+    1.f, -13.f, 10.f, -9.f, 18.f, -13.f, 22.f, -13.f, 25.f, -9.f, 34.f, -0.f, 38.f, -9.f, 49.f, -9.f, 59.f, -9.f, 65.f, -13.f, 68.f, -13.f, 77.f, -0.f,
+    0.f, -8.f, 7.f, -6.f, 12.f, -7.f, 18.f, -7.f, 23.f, -11.f, 25.f, -0.f, 27.f, -7.f, 32.f, -11.f, 33.f, -11.f, 37.f, -8.f, 44.f, -11.f, 45.f, -11.f, 49.f, -8.f, 55.f, -0.f, 59.f, -10.f, 70.f, -13.f, 77.f, -10.f, 82.f, -10.f, 90.f, -0.f,
+    1.f, -10.f, 9.f, -10.f, 14.f, -13.f, 22.f, -10.f, 30.f, -0.f,
+    1.f, -12.f, 12.f, -9.f, 20.f, -13.f, 24.f, -13.f, 27.f, -9.f, 36.f, -0.f, 40.f, -9.f, 51.f, -9.f, 61.f, -9.f, 67.f, -13.f, 70.f, -13.f, 79.f, -0.f,
+    0.f, -13.f, 10.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -0.f, 44.f, -10.f, 55.f, -13.f, 62.f, -10.f, 67.f, -10.f, 75.f, -0.f,
+    1.f, -10.f, 9.f, -10.f, 14.f, -13.f, 22.f, -10.f, 32.f, -2.f, 35.f, -11.f,
+    1.f, -10.f, 12.f, -13.f, 19.f, -10.f, 24.f, -10.f, 32.f, -0.f, 37.f, -10.f, 45.f, -10.f, 50.f, -13.f, 58.f, -10.f, 66.f, -0.f,
+    1.f, -13.f, 10.f, -9.f, 18.f, -13.f, 22.f, -13.f, 25.f, -9.f, 34.f, -0.f, 38.f, -9.f, 49.f, -9.f, 59.f, -9.f, 65.f, -13.f, 68.f, -13.f, 77.f, -0.f,
+    0.f, -8.f, 7.f, -6.f, 12.f, -7.f, 18.f, -7.f, 23.f, -11.f, 25.f, -0.f, 27.f, -7.f, 32.f, -11.f, 33.f, -11.f, 37.f, -8.f, 44.f, -11.f, 45.f, -11.f, 49.f, -8.f, 55.f, -0.f,
   };
   struct LineRun line01 =
   {
@@ -2706,24 +2707,24 @@ int UtcDaliTextUpdateLayout03(void)
   Size layoutSize(92.f, 380.f);
   float positions[] =
   {
-    1.f, 3.f, 12.f, 6.f, 20.f, 2.f, 24.f, 2.f, 27.f, 6.f, 36.f, 15.f, 40.f, 6.f, 51.f, 6.f, 61.f, 6.f, 67.f, 2.f, 70.f, 2.f, 79.f, 15.f,
-    0.f, 22.f, 10.f, 26.f, 18.f, 26.f, 30.f, 26.f, 39.f, 35.f, 44.f, 25.f, 55.f, 22.f, 62.f, 25.f, 67.f, 25.f, 75.f, 35.f,
-    1.f, 45.f, 9.f, 45.f, 14.f, 42.f, 22.f, 45.f, 32.f, 53.f, 35.f, 44.f,
-    0.f, 67.f, 7.f, 69.f, 12.f, 68.f, 18.f, 68.f, 23.f, 64.f, 25.f, 75.f, 27.f, 68.f, 32.f, 64.f, 33.f, 64.f, 37.f, 67.f, 44.f, 64.f, 45.f, 64.f, 49.f, 67.f, 55.f, 75.f, 59.f, 62.f, 68.f, 66.f, 76.f, 62.f, 80.f, 62.f, 83.f, 66.f, 92.f, 75.f,
-    0.f, 86.f, 11.f, 86.f, 21.f, 86.f, 27.f, 82.f, 30.f, 82.f, 39.f, 95.f, 44.f, 85.f, 55.f, 82.f, 62.f, 85.f, 67.f, 85.f, 75.f, 95.f,
-    1.f, 105.f, 9.f, 105.f, 14.f, 102.f, 22.f, 105.f, 30.f, 115.f,
-    1.f, 125.f, 12.f, 122.f, 19.f, 125.f, 24.f, 125.f, 32.f, 135.f, 37.f, 125.f, 45.f, 125.f, 50.f, 122.f, 58.f, 125.f, 66.f, 135.f,
-    1.f, 142.f, 10.f, 146.f, 18.f, 142.f, 22.f, 142.f, 25.f, 146.f, 34.f, 155.f, 38.f, 146.f, 49.f, 146.f, 59.f, 146.f, 65.f, 142.f, 68.f, 142.f, 77.f, 155.f,
-    0.f, 162.f, 10.f, 166.f, 18.f, 166.f, 30.f, 166.f, 39.f, 172.f, 42.f, 163.f,
-    1.f, 182.f, 10.f, 186.f, 18.f, 182.f, 22.f, 182.f, 25.f, 186.f, 34.f, 195.f, 38.f, 186.f, 49.f, 186.f, 59.f, 186.f, 65.f, 182.f, 68.f, 182.f, 77.f, 195.f,
-    0.f, 207.f, 7.f, 209.f, 12.f, 208.f, 18.f, 208.f, 23.f, 204.f, 25.f, 215.f, 27.f, 208.f, 32.f, 204.f, 33.f, 204.f, 37.f, 207.f, 44.f, 204.f, 45.f, 204.f, 49.f, 207.f, 55.f, 215.f, 59.f, 205.f, 70.f, 202.f, 77.f, 205.f, 82.f, 205.f, 90.f, 215.f,
-    1.f, 225.f, 9.f, 225.f, 14.f, 222.f, 22.f, 225.f, 30.f, 235.f,
-    1.f, 243.f, 12.f, 246.f, 20.f, 242.f, 24.f, 242.f, 27.f, 246.f, 36.f, 255.f, 40.f, 246.f, 51.f, 246.f, 61.f, 246.f, 67.f, 242.f, 70.f, 242.f, 79.f, 255.f,
-    0.f, 262.f, 10.f, 266.f, 18.f, 266.f, 30.f, 266.f, 39.f, 275.f, 44.f, 265.f, 55.f, 262.f, 62.f, 265.f, 67.f, 265.f, 75.f, 275.f,
-    1.f, 285.f, 9.f, 285.f, 14.f, 282.f, 22.f, 285.f, 32.f, 293.f, 35.f, 284.f,
-    1.f, 305.f, 12.f, 302.f, 19.f, 305.f, 24.f, 305.f, 32.f, 315.f, 37.f, 305.f, 45.f, 305.f, 50.f, 302.f, 58.f, 305.f, 66.f, 315.f,
-    1.f, 322.f, 10.f, 326.f, 18.f, 322.f, 22.f, 322.f, 25.f, 326.f, 34.f, 335.f, 38.f, 326.f, 49.f, 326.f, 59.f, 326.f, 65.f, 322.f, 68.f, 322.f, 77.f, 335.f,
-    0.f, 347.f, 7.f, 349.f, 12.f, 348.f, 18.f, 348.f, 23.f, 344.f, 25.f, 355.f, 27.f, 348.f, 32.f, 344.f, 33.f, 344.f, 37.f, 347.f, 44.f, 344.f, 45.f, 344.f, 49.f, 347.f, 55.f, 355.f,
+    1.f, -12.f, 12.f, -9.f, 20.f, -13.f, 24.f, -13.f, 27.f, -9.f, 36.f, -0.f, 40.f, -9.f, 51.f, -9.f, 61.f, -9.f, 67.f, -13.f, 70.f, -13.f, 79.f, -0.f,
+    0.f, -13.f, 10.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -0.f, 44.f, -10.f, 55.f, -13.f, 62.f, -10.f, 67.f, -10.f, 75.f, -0.f,
+    1.f, -10.f, 9.f, -10.f, 14.f, -13.f, 22.f, -10.f, 32.f, -2.f, 35.f, -11.f,
+    0.f, -8.f, 7.f, -6.f, 12.f, -7.f, 18.f, -7.f, 23.f, -11.f, 25.f, -0.f, 27.f, -7.f, 32.f, -11.f, 33.f, -11.f, 37.f, -8.f, 44.f, -11.f, 45.f, -11.f, 49.f, -8.f, 55.f, -0.f, 59.f, -13.f, 68.f, -9.f, 76.f, -13.f, 80.f, -13.f, 83.f, -9.f, 92.f, -0.f,
+    0.f, -9.f, 11.f, -9.f, 21.f, -9.f, 27.f, -13.f, 30.f, -13.f, 39.f, -0.f, 44.f, -10.f, 55.f, -13.f, 62.f, -10.f, 67.f, -10.f, 75.f, -0.f,
+    1.f, -10.f, 9.f, -10.f, 14.f, -13.f, 22.f, -10.f, 30.f, -0.f,
+    1.f, -10.f, 12.f, -13.f, 19.f, -10.f, 24.f, -10.f, 32.f, -0.f, 37.f, -10.f, 45.f, -10.f, 50.f, -13.f, 58.f, -10.f, 66.f, -0.f,
+    1.f, -13.f, 10.f, -9.f, 18.f, -13.f, 22.f, -13.f, 25.f, -9.f, 34.f, -0.f, 38.f, -9.f, 49.f, -9.f, 59.f, -9.f, 65.f, -13.f, 68.f, -13.f, 77.f, -0.f,
+    0.f, -13.f, 10.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -3.f, 42.f, -12.f,
+    1.f, -13.f, 10.f, -9.f, 18.f, -13.f, 22.f, -13.f, 25.f, -9.f, 34.f, -0.f, 38.f, -9.f, 49.f, -9.f, 59.f, -9.f, 65.f, -13.f, 68.f, -13.f, 77.f, -0.f,
+    0.f, -8.f, 7.f, -6.f, 12.f, -7.f, 18.f, -7.f, 23.f, -11.f, 25.f, -0.f, 27.f, -7.f, 32.f, -11.f, 33.f, -11.f, 37.f, -8.f, 44.f, -11.f, 45.f, -11.f, 49.f, -8.f, 55.f, -0.f, 59.f, -10.f, 70.f, -13.f, 77.f, -10.f, 82.f, -10.f, 90.f, -0.f,
+    1.f, -10.f, 9.f, -10.f, 14.f, -13.f, 22.f, -10.f, 30.f, -0.f,
+    1.f, -12.f, 12.f, -9.f, 20.f, -13.f, 24.f, -13.f, 27.f, -9.f, 36.f, -0.f, 40.f, -9.f, 51.f, -9.f, 61.f, -9.f, 67.f, -13.f, 70.f, -13.f, 79.f, -0.f,
+    0.f, -13.f, 10.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -0.f, 44.f, -10.f, 55.f, -13.f, 62.f, -10.f, 67.f, -10.f, 75.f, -0.f,
+    1.f, -10.f, 9.f, -10.f, 14.f, -13.f, 22.f, -10.f, 32.f, -2.f, 35.f, -11.f,
+    1.f, -10.f, 12.f, -13.f, 19.f, -10.f, 24.f, -10.f, 32.f, -0.f, 37.f, -10.f, 45.f, -10.f, 50.f, -13.f, 58.f, -10.f, 66.f, -0.f,
+    1.f, -13.f, 10.f, -9.f, 18.f, -13.f, 22.f, -13.f, 25.f, -9.f, 34.f, -0.f, 38.f, -9.f, 49.f, -9.f, 59.f, -9.f, 65.f, -13.f, 68.f, -13.f, 77.f, -0.f,
+    0.f, -8.f, 7.f, -6.f, 12.f, -7.f, 18.f, -7.f, 23.f, -11.f, 25.f, -0.f, 27.f, -7.f, 32.f, -11.f, 33.f, -11.f, 37.f, -8.f, 44.f, -11.f, 45.f, -11.f, 49.f, -8.f, 55.f, -0.f,
   };
   struct LineRun line01 =
   {
@@ -3049,7 +3050,7 @@ int UtcDaliTextLayoutEllipsis01(void)
 
   float positions[] =
   {
-    1.f, 3.f, 12.f, 6.f, 20.f, 2.f, 24.f, 2.f, 27.f, 6.f, 36.f, 15.f, 40.f, 6.f, 51.f, 6.f, 61.f, 6.f, 67.f, 2.f, 70.f, 2.f, 79.f, 15.f, 83.f, 2.f
+    1.f, -12.f, 12.f, -9.f, 20.f, -13.f, 24.f, -13.f, 27.f, -9.f, 36.f, -0.f, 40.f, -9.f, 51.f, -9.f, 61.f, -9.f, 67.f, -13.f, 70.f, -13.f, 79.f, -0.f, 83.f, -13.f,
   };
 
   Size textArea( 100.f, 50.f );
@@ -3138,8 +3139,8 @@ int UtcDaliTextLayoutEllipsis02(void)
 
   float positions[] =
   {
-    1.f,  3.f, 12.f,  6.f, 20.f,  2.f, 24.f,  2.f, 27.f,  6.f, 36.f, 15.f, 40.f,  6.f, 51.f,  6.f, 61.f,  6.f, 67.f,  2.f, 70.f,  2.f, 79.f, 15.f,
-    0.f, 22.f, 10.f, 26.f, 18.f, 26.f, 30.f, 26.f, 39.f, 35.f, 44.f, 22.f, 53.f, 26.f, 61.f, 22.f, 65.f, 22.f, 68.f, 26.f, 77.f, 35.f, 81.f, 26.f
+    1.f, -12.f, 12.f, -9.f, 20.f, -13.f, 24.f, -13.f, 27.f, -9.f, 36.f, -0.f, 40.f, -9.f, 51.f, -9.f, 61.f, -9.f, 67.f, -13.f, 70.f, -13.f, 79.f, -0.f,
+    0.f, -13.f, 10.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -0.f, 44.f, -13.f, 53.f, -9.f, 61.f, -13.f, 65.f, -13.f, 68.f, -9.f, 77.f, -0.f, 81.f, -9.f,
   };
 
   Size textArea( 100.f, 50.f );
@@ -3281,7 +3282,7 @@ int UtcDaliTextLayoutEllipsis03(void)
 
   float positions[] =
   {
-    1.f, 5.f, 12.f, 2.f, 19.f, 5.f, 24.f, 5.f, 32.f, 15.f, 37.f, 5.f, 45.f, 5.f, 50.f, 2.f, 58.f, 5.f, 66.f, 15.f, 69.f, 7.f, 76.f, 9.f, 81.f, 8.f, 87.f, 8.f, 92.f, 4.f, 94.f, 15.f,
+    1.f, -10.f, 12.f, -13.f, 19.f, -10.f, 24.f, -10.f, 32.f, -0.f, 37.f, -10.f, 45.f, -10.f, 50.f, -13.f, 58.f, -10.f, 66.f, -0.f, 69.f, -8.f, 76.f, -6.f, 81.f, -7.f, 87.f, -7.f, 92.f, -11.f, 94.f, -0.f,
   };
 
   Size textArea( 100.f, 50.f );
@@ -3436,8 +3437,8 @@ int UtcDaliTextLayoutEllipsis04(void)
 
   float positions[] =
   {
-    1.f,  5.f, 12.f,  2.f, 19.f,  5.f, 24.f,  5.f, 32.f, 15.f, 37.f,  5.f, 45.f,  5.f, 50.f,  2.f, 58.f,  5.f, 66.f, 15.f, 69.f,  7.f, 76.f,  9.f, 81.f,  8.f, 87.f,  8.f, 92.f,  4.f, 94.f, 15.f,
-    0.f, 28.f,  5.f, 24.f,  6.f, 24.f, 10.f, 27.f, 17.f, 24.f, 18.f, 24.f, 22.f, 27.f, 28.f, 35.f, 32.f, 25.f, 43.f, 22.f, 50.f, 25.f, 55.f, 25.f, 63.f, 35.f, 68.f, 25.f, 76.f, 25.f, 81.f, 22.f, 89.f, 25.f, 97.f, 35.f
+    1.f, -10.f, 12.f, -13.f, 19.f, -10.f, 24.f, -10.f, 32.f, -0.f, 37.f, -10.f, 45.f, -10.f, 50.f, -13.f, 58.f, -10.f, 66.f, -0.f, 69.f, -8.f, 76.f, -6.f, 81.f, -7.f, 87.f, -7.f, 92.f, -11.f, 94.f, -0.f,
+    0.f, -7.f, 5.f, -11.f, 6.f, -11.f, 10.f, -8.f, 17.f, -11.f, 18.f, -11.f, 22.f, -8.f, 28.f, -0.f, 32.f, -10.f, 43.f, -13.f, 50.f, -10.f, 55.f, -10.f, 63.f, -0.f, 68.f, -10.f, 76.f, -10.f, 81.f, -13.f, 89.f, -10.f, 97.f, -0.f,
   };
 
   Size textArea( 100.f, 50.f );
@@ -3498,7 +3499,7 @@ int UtcDaliTextReorderLayout01(void)
 
   float positions[] =
   {
-    1.f, 3.f, 12.f, 6.f, 20.f, 2.f, 24.f, 2.f, 27.f, 6.f, 36.f, 15.f, 40.f, 6.f, 51.f, 6.f, 61.f, 6.f, 67.f, 2.f, 70.f, 2.f
+    1.f, -12.f, 12.f, -9.f, 20.f, -13.f, 24.f, -13.f, 27.f, -9.f, 36.f, -0.f, 40.f, -9.f, 51.f, -9.f, 61.f, -9.f, 67.f, -13.f, 70.f, -13.f,
   };
 
   Size textArea( 100.f, 300.f );
@@ -3618,12 +3619,12 @@ int UtcDaliTextReorderLayout02(void)
 
   float positions[] =
   {
-    87.f,  5.f, 79.f,  2.f, 74.f,  5.f, 66.f,  5.f, 61.f, 15.f, 53.f,  5.f, 48.f,  5.f, 41.f,  2.f, 32.f,  5.f, 27.f, 15.f, 20.f,  7.f, 15.f,  9.f,  8.f,  8.f,  5.f,  8.f,  4.f,  4.f,  0.f, 15.f,
-    23.f, 28.f, 22.f, 24.f, 17.f, 24.f, 12.f, 27.f, 10.f, 24.f,  5.f, 24.f,  0.f, 27.f,  0.f, 35.f,
-    0.f, 47.f, 7.f, 49.f, 12.f, 48.f, 18.f, 48.f, 23.f, 44.f, 25.f, 55.f, 27.f, 48.f, 32.f, 44.f, 33.f, 44.f, 37.f, 47.f, 44.f, 44.f, 45.f, 44.f, 49.f, 47.f, 55.f, 55.f, 59.f, 45.f, 70.f, 42.f, 77.f, 45.f, 82.f, 45.f, 90.f, 55.f,
-    1.f, 65.f, 9.f, 65.f, 14.f, 62.f, 22.f, 65.f, 30.f, 75.f,
-    1.f, 85.f, 12.f, 82.f, 19.f, 85.f, 24.f, 85.f, 32.f, 95.f, 37.f, 85.f, 45.f, 85.f, 50.f, 82.f, 58.f, 85.f, 66.f, 95.f, 69.f, 87.f, 76.f, 89.f, 81.f, 88.f, 87.f, 88.f, 92.f, 84.f, 94.f, 95.f,
-    0.f, 108.f, 5.f, 104.f, 6.f, 104.f, 10.f, 107.f, 17.f, 104.f, 18.f, 104.f, 22.f, 107.f, 30.f, 113.f
+    87.f, -10.f, 79.f, -13.f, 74.f, -10.f, 66.f, -10.f, 61.f, -0.f, 53.f, -10.f, 48.f, -10.f, 41.f, -13.f, 32.f, -10.f, 27.f, -0.f, 20.f, -8.f, 15.f, -6.f, 8.f, -7.f, 5.f, -7.f, 4.f, -11.f, 0.f, -0.f,
+    23.f, -7.f, 22.f, -11.f, 17.f, -11.f, 12.f, -8.f, 10.f, -11.f, 5.f, -11.f, 0.f, -8.f, 0.f, -0.f,
+    0.f, -8.f, 7.f, -6.f, 12.f, -7.f, 18.f, -7.f, 23.f, -11.f, 25.f, -0.f, 27.f, -7.f, 32.f, -11.f, 33.f, -11.f, 37.f, -8.f, 44.f, -11.f, 45.f, -11.f, 49.f, -8.f, 55.f, -0.f, 59.f, -10.f, 70.f, -13.f, 77.f, -10.f, 82.f, -10.f, 90.f, -0.f,
+    1.f, -10.f, 9.f, -10.f, 14.f, -13.f, 22.f, -10.f, 30.f, -0.f,
+    1.f, -10.f, 12.f, -13.f, 19.f, -10.f, 24.f, -10.f, 32.f, -0.f, 37.f, -10.f, 45.f, -10.f, 50.f, -13.f, 58.f, -10.f, 66.f, -0.f, 69.f, -8.f, 76.f, -6.f, 81.f, -7.f, 87.f, -7.f, 92.f, -11.f, 94.f, -0.f,
+    0.f, -7.f, 5.f, -11.f, 6.f, -11.f, 10.f, -8.f, 17.f, -11.f, 18.f, -11.f, 22.f, -8.f, 30.f, -2.f,
   };
 
   Size textArea( 100.f, 300.f );
@@ -3745,12 +3746,12 @@ int UtcDaliTextReorderLayout03(void)
 
   float positions[] =
   {
-    1.f,  5.f, 12.f,  2.f, 19.f,  5.f, 24.f,  5.f, 32.f, 15.f, 37.f,  5.f, 45.f,  5.f, 50.f,  2.f, 58.f,  5.f, 66.f, 15.f, 69.f,  7.f, 76.f,  9.f, 81.f,  8.f, 87.f,  8.f, 92.f, 4.f, 94.f, 15.f,
-    0.f, 28.f,  5.f, 24.f,  6.f, 24.f, 10.f, 27.f, 17.f, 24.f, 18.f, 24.f, 22.f, 27.f, 28.f, 35.f,
-    86.f, 47.f, 81.f, 49.f, 74.f, 48.f, 71.f, 48.f, 70.f, 44.f, 66.f, 55.f, 62.f, 48.f, 61.f, 44.f, 56.f, 44.f, 51.f, 47.f, 49.f, 44.f, 44.f, 44.f, 39.f, 47.f, 36.f, 55.f, 26.f, 45.f, 18.f, 42.f, 13.f, 45.f,  5.f, 45.f,  0.f, 55.f,
-    22.f, 65.f, 17.f, 65.f, 10.f, 62.f,  1.f, 65.f,  0.f, 75.f,
-    1.f, 85.f, 12.f, 82.f, 19.f, 85.f, 24.f, 85.f, 32.f, 95.f, 37.f, 85.f, 45.f, 85.f, 50.f, 82.f, 58.f, 85.f, 66.f, 95.f, 69.f, 87.f, 76.f, 89.f, 81.f, 88.f, 87.f, 88.f, 92.f, 84.f, 94.f, 95.f,
-    0.f, 108.f,  5.f, 104.f,  6.f, 104.f, 10.f, 107.f, 17.f, 104.f, 18.f, 104.f, 22.f, 107.f, 30.f, 113.f
+    1.f, -10.f, 12.f, -13.f, 19.f, -10.f, 24.f, -10.f, 32.f, -0.f, 37.f, -10.f, 45.f, -10.f, 50.f, -13.f, 58.f, -10.f, 66.f, -0.f, 69.f, -8.f, 76.f, -6.f, 81.f, -7.f, 87.f, -7.f, 92.f, -11.f, 94.f, -0.f,
+    0.f, -7.f,  5.f, -11.f, 6.f, -11.f, 10.f, -8.f, 17.f, -11.f, 18.f, -11.f, 22.f, -8.f, 28.f, -0.f,
+    86.f, -8.f, 81.f, -6.f, 74.f, -7.f, 71.f, -7.f, 70.f, -11.f, 66.f, -0.f, 62.f, -7.f, 61.f, -11.f, 56.f, -11.f, 51.f, -8.f, 49.f, -11.f, 44.f, -11.f, 39.f, -8.f, 36.f, -0.f, 26.f, -10.f, 18.f, -13.f, 13.f, -10.f, 5.f, -10.f, 0.f, -0.f,
+    22.f, -10.f, 17.f, -10.f, 10.f, -13.f, 1.f, -10.f, 0.f, -0.f,
+    1.f, -10.f, 12.f, -13.f, 19.f, -10.f, 24.f, -10.f, 32.f, -0.f, 37.f, -10.f, 45.f, -10.f, 50.f, -13.f, 58.f, -10.f, 66.f, -0.f, 69.f, -8.f, 76.f, -6.f, 81.f, -7.f, 87.f, -7.f, 92.f, -11.f, 94.f, -0.f,
+    0.f, -7.f, 5.f, -11.f, 6.f, -11.f, 10.f, -8.f, 17.f, -11.f, 18.f, -11.f, 22.f, -8.f, 30.f, -2.f,
   };
 
   Size textArea( 100.f, 300.f );
@@ -3872,12 +3873,12 @@ int UtcDaliTextReorderLayout04(void)
 
   float positions[] =
   {
-    1.f,  5.f, 12.f,  2.f, 19.f,  5.f, 24.f,  5.f, 32.f, 15.f, 37.f,  5.f, 45.f,  5.f, 50.f,  2.f, 58.f,  5.f, 66.f, 15.f, 69.f,  7.f, 76.f,  9.f, 81.f,  8.f, 87.f,  8.f, 92.f, 4.f, 94.f, 15.f,
-    0.f, 28.f,  5.f, 24.f,  6.f, 24.f, 10.f, 27.f, 17.f, 24.f, 18.f, 24.f, 22.f, 27.f, 28.f, 35.f,
-    0.f, 47.f,  7.f, 49.f, 12.f, 48.f, 18.f, 48.f, 23.f, 44.f, 25.f, 55.f, 27.f, 48.f, 32.f, 44.f, 33.f, 44.f, 37.f, 47.f, 44.f, 44.f, 45.f, 44.f, 49.f, 47.f, 55.f, 55.f, 59.f, 45.f, 70.f, 42.f, 77.f, 45.f, 82.f, 45.f, 90.f, 55.f,
-    1.f, 65.f,  9.f, 65.f, 14.f, 62.f, 22.f, 65.f, 30.f, 75.f,
-    87.f, 85.f, 79.f, 82.f, 74.f, 85.f, 66.f, 85.f, 61.f, 95.f, 53.f, 85.f, 48.f, 85.f, 41.f, 82.f, 32.f, 85.f, 27.f, 95.f, 20.f, 87.f, 15.f, 89.f,  8.f, 88.f,  5.f, 88.f,  4.f, 84.f,  0.f, 95.f,
-    28.f, 108.f, 27.f, 104.f, 22.f, 104.f, 17.f, 107.f, 15.f, 104.f, 10.f, 104.f,  5.f, 107.f,  2.f, 113.f
+    1.f, -10.f, 12.f, -13.f, 19.f, -10.f, 24.f, -10.f, 32.f, -0.f, 37.f, -10.f, 45.f, -10.f, 50.f, -13.f, 58.f, -10.f, 66.f, -0.f, 69.f, -8.f, 76.f, -6.f, 81.f, -7.f, 87.f, -7.f, 92.f, -11.f, 94.f, -0.f,
+    0.f, -7.f, 5.f, -11.f, 6.f, -11.f, 10.f, -8.f, 17.f, -11.f, 18.f, -11.f, 22.f, -8.f, 28.f, -0.f,
+    0.f, -8.f, 7.f, -6.f, 12.f, -7.f, 18.f, -7.f, 23.f, -11.f, 25.f, -0.f, 27.f, -7.f, 32.f, -11.f, 33.f, -11.f, 37.f, -8.f, 44.f, -11.f, 45.f, -11.f, 49.f, -8.f, 55.f, -0.f, 59.f, -10.f, 70.f, -13.f, 77.f, -10.f, 82.f, -10.f, 90.f, -0.f,
+    1.f, -10.f, 9.f, -10.f, 14.f, -13.f, 22.f, -10.f, 30.f, -0.f,
+    87.f, -10.f, 79.f, -13.f, 74.f, -10.f, 66.f, -10.f, 61.f, -0.f, 53.f, -10.f, 48.f, -10.f, 41.f, -13.f, 32.f, -10.f, 27.f, -0.f, 20.f, -8.f, 15.f, -6.f, 8.f, -7.f, 5.f, -7.f, 4.f, -11.f, 0.f, -0.f,
+    28.f, -7.f, 27.f, -11.f, 22.f, -11.f, 17.f, -8.f, 15.f, -11.f, 10.f, -11.f, 5.f, -8.f, 2.f, -2.f,
   };
 
   Size textArea( 100.f, 300.f );
index fe6d4cb..115a0d1 100644 (file)
@@ -80,10 +80,11 @@ bool SetGlyphsPerCharacterTest( const SetGlyphsPerCharacterData& data )
                    logicalModel,
                    visualModel );
 
-  // 2) Clear the model.
   Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
   Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
 
+  // 2) Clear the model.
+
   GlyphIndex startGlyphIndex = 0u;
   if( 0u != charactersToGlyph.Count() )
   {
@@ -159,10 +160,11 @@ bool SetCharacterToGlyphTest( const SetCharacterToGlyphData& data )
                    logicalModel,
                    visualModel );
 
-  // 2) Clear the model.
   Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
   Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
 
+  // 2) Clear the model.
+
   GlyphIndex startGlyphIndex = 0u;
   if( 0u != charactersToGlyph.Count() )
   {
index aff7eb7..4ec0eba 100644 (file)
@@ -295,6 +295,8 @@ void CreateTextModel( const std::string& text,
   // The initial glyph and the number of glyphs to layout.
   layoutParameters.startGlyphIndex = 0u;
   layoutParameters.numberOfGlyphs = numberOfGlyphs;
+  layoutParameters.startLineIndex = 0u;
+  layoutParameters.estimatedNumberOfLines = logicalModel->mParagraphInfo.Count();
 
   layoutEngine.LayoutText( layoutParameters,
                            glyphPositions,
index 9d81116..0b9e39d 100644 (file)
@@ -47,26 +47,6 @@ const float MAX_FLOAT = std::numeric_limits<float>::max();
 const bool RTL = true;
 const float CURSOR_WIDTH = 1.f;
 
-Length CountParagraphs( const LayoutParameters& layoutParameters )
-{
-  Length numberOfParagraphs = 0u;
-
-  const CharacterIndex startCharacterIndex = *( layoutParameters.glyphsToCharactersBuffer + layoutParameters.startGlyphIndex );
-
-  const GlyphIndex lastGlyphIndex = layoutParameters.startGlyphIndex + layoutParameters.numberOfGlyphs - 1u;
-  const CharacterIndex lastCharacterIndexPlusOne = *( layoutParameters.glyphsToCharactersBuffer + lastGlyphIndex ) + *( layoutParameters.charactersPerGlyphBuffer + lastGlyphIndex );
-
-  for( CharacterIndex index = startCharacterIndex; index < lastCharacterIndexPlusOne; ++index )
-  {
-    if( TextAbstraction::LINE_MUST_BREAK == *( layoutParameters.lineBreakInfoBuffer + index ) )
-    {
-      ++numberOfParagraphs;
-    }
-  }
-
-  return numberOfParagraphs;
-}
-
 } //namespace
 
 /**
@@ -489,7 +469,6 @@ struct LayoutEngine::Impl
 
   void SetGlyphPositions( const GlyphInfo* const glyphsBuffer,
                           Length numberOfGlyphs,
-                          float penY,
                           Vector2* glyphPositionsBuffer )
   {
     // Traverse the glyphs and set the positions.
@@ -507,7 +486,7 @@ struct LayoutEngine::Impl
       Vector2& position = *( glyphPositionsBuffer + i );
 
       position.x = penX + glyph.xBearing;
-      position.y = penY - glyph.yBearing;
+      position.y = -glyph.yBearing;
 
       penX += glyph.advance;
     }
@@ -621,7 +600,6 @@ struct LayoutEngine::Impl
 
       SetGlyphPositions( layoutParameters.glyphsBuffer + lineRun->glyphRun.glyphIndex,
                          ellipsisLayout.numberOfGlyphs,
-                         penY,
                          glyphPositionsBuffer + lineRun->glyphRun.glyphIndex - layoutParameters.startGlyphIndex );
     }
 
@@ -691,17 +669,17 @@ struct LayoutEngine::Impl
    * @brief Updates the text layout with the last laid-out line.
    *
    * @param[in] layoutParameters The parameters needed to layout the text.
-   * @param[in] layout The line layout.
+   * @param[in] characterIndex The character index of the line.
+   * @param[in] glyphIndex The glyph index of the line.
    * @param[in,out] layoutSize The text's layout size.
    * @param[in,out] linesBuffer Pointer to the line's buffer.
-   * @param[in] index Index to the vector of glyphs.
    * @param[in,out] numberOfLines The number of laid-out lines.
    */
   void UpdateTextLayout( const LayoutParameters& layoutParameters,
-                         const LineLayout& layout,
+                         CharacterIndex characterIndex,
+                         GlyphIndex glyphIndex,
                          Size& layoutSize,
                          LineRun* linesBuffer,
-                         GlyphIndex index,
                          Length& numberOfLines )
   {
     // Need to add a new line with no characters but with height to increase the layoutSize.height
@@ -713,9 +691,9 @@ struct LayoutEngine::Impl
     LineRun& lineRun = *( linesBuffer + numberOfLines );
     ++numberOfLines;
 
-    lineRun.glyphRun.glyphIndex = index + layout.numberOfGlyphs;
+    lineRun.glyphRun.glyphIndex = glyphIndex;
     lineRun.glyphRun.numberOfGlyphs = 0u;
-    lineRun.characterRun.characterIndex = layout.characterIndex + layout.numberOfCharacters;
+    lineRun.characterRun.characterIndex = characterIndex;
     lineRun.characterRun.numberOfCharacters = 0u;
     lineRun.width = 0.f;
     lineRun.ascender = fontMetrics.ascender;
@@ -792,10 +770,49 @@ struct LayoutEngine::Impl
 
     if( 0u == layoutParameters.numberOfGlyphs )
     {
-      // Nothing to do if there are no glyphs to layout.
+      // Add an extra line if the last character is a new paragraph character and the last line doesn't have zero characters.
+      if( layoutParameters.isLastNewParagraph )
+      {
+        Length numberOfLines = lines.Count();
+        if( 0u != numberOfLines )
+        {
+          const LineRun& lastLine = *( lines.End() - 1u );
+
+          if( 0u != lastLine.characterRun.numberOfCharacters )
+          {
+            // Need to add a new line with no characters but with height to increase the layoutSize.height
+            LineRun newLine;
+            lines.PushBack( newLine );
+
+            UpdateTextLayout( layoutParameters,
+                              lastLine.characterRun.characterIndex + lastLine.characterRun.numberOfCharacters,
+                              lastLine.glyphRun.glyphIndex + lastLine.glyphRun.numberOfGlyphs,
+                              layoutSize,
+                              lines.Begin(),
+                              numberOfLines );
+          }
+        }
+      }
+
+      // Nothing else do if there are no glyphs to layout.
       return false;
     }
 
+    const GlyphIndex lastGlyphPlusOne = layoutParameters.startGlyphIndex + layoutParameters.numberOfGlyphs;
+
+    // In a previous layout, an extra line with no characters may have been added if the text ended with a new paragraph character.
+    // This extra line needs to be removed.
+    if( 0u != lines.Count() )
+    {
+      Vector<LineRun>::Iterator lastLine = lines.End() - 1u;
+
+      if( ( 0u == lastLine->characterRun.numberOfCharacters ) &&
+          ( lastGlyphPlusOne == layoutParameters.totalNumberOfGlyphs ) )
+      {
+        lines.Remove( lastLine );
+      }
+    }
+
     // Set the first paragraph's direction.
     CharacterDirection paragraphDirection = ( NULL != layoutParameters.characterDirectionBuffer ) ? *layoutParameters.characterDirectionBuffer : !RTL;
 
@@ -809,8 +826,7 @@ struct LayoutEngine::Impl
     Vector<LineRun> newLines;
 
     // Estimate the number of lines.
-    // TODO: In a next patch the paragraphs are properly managed and this can be removed.
-    Length linesCapacity = CountParagraphs( layoutParameters );
+    Length linesCapacity = layoutParameters.estimatedNumberOfLines;
     Length numberOfLines = 0u;
 
     if( updateCurrentBuffer )
@@ -832,7 +848,6 @@ struct LayoutEngine::Impl
     float penY = SetParagraphOffset( lines,
                                      layoutParameters.startLineIndex );
 
-    const GlyphIndex lastGlyphPlusOne = layoutParameters.startGlyphIndex + layoutParameters.numberOfGlyphs;
     for( GlyphIndex index = layoutParameters.startGlyphIndex; index < lastGlyphPlusOne; )
     {
       CharacterDirection currentParagraphDirection = paragraphDirection;
@@ -908,7 +923,9 @@ struct LayoutEngine::Impl
                           numberOfLines,
                           isLastLine );
 
-        if( isLastLine &&
+        const GlyphIndex nextIndex = index + layout.numberOfGlyphs;
+
+        if( ( nextIndex == layoutParameters.totalNumberOfGlyphs ) &&
             layoutParameters.isLastNewParagraph &&
             ( mLayout == MULTI_LINE_BOX ) )
         {
@@ -926,25 +943,23 @@ struct LayoutEngine::Impl
           }
 
           UpdateTextLayout( layoutParameters,
-                            layout,
+                            layout.characterIndex + layout.numberOfCharacters,
+                            index + layout.numberOfGlyphs,
                             layoutSize,
                             linesBuffer,
-                            index,
                             numberOfLines );
         } // whether to add a last line.
 
         // Sets the positions of the glyphs.
         SetGlyphPositions( layoutParameters.glyphsBuffer + index,
                            layout.numberOfGlyphs,
-                           penY,
                            glyphPositionsBuffer + index - layoutParameters.startGlyphIndex );
 
         // Updates the vertical pen's position.
         penY += -layout.descender;
 
         // Increase the glyph index.
-        index += layout.numberOfGlyphs;
-
+        index = nextIndex;
       } // no ellipsis
     } // end for() traversing glyphs.
 
@@ -953,6 +968,7 @@ struct LayoutEngine::Impl
       glyphPositions.Insert( glyphPositions.Begin() + layoutParameters.startGlyphIndex,
                              newGlyphPositions.Begin(),
                              newGlyphPositions.End() );
+      glyphPositions.Resize( layoutParameters.totalNumberOfGlyphs );
 
       newLines.Resize( numberOfLines );
 
index 238dade..8d875bf 100644 (file)
@@ -82,6 +82,7 @@ struct LayoutParameters
     numberOfGlyphs( 0u ),
     totalNumberOfGlyphs( totalNumberOfGlyphs ),
     startLineIndex( 0u ),
+    estimatedNumberOfLines( 0u ),
     isLastNewParagraph( false )
   {}
 
@@ -101,6 +102,7 @@ struct LayoutParameters
   Length                          numberOfGlyphs;                  ///< The number of glyphs to layout.
   Length                          totalNumberOfGlyphs;             ///< The number of glyphs.
   LineIndex                       startLineIndex;                  ///< The line index where to insert the new lines.
+  Length                          estimatedNumberOfLines;          ///< The estimated number of lines.
   bool                            isLastNewParagraph;              ///< Whether the last character is a new paragraph character.
 };
 
index 5571f94..468ab0c 100644 (file)
@@ -29,6 +29,7 @@
 #include <dali-toolkit/internal/text/multi-language-support.h>
 #include <dali-toolkit/internal/text/segmentation.h>
 #include <dali-toolkit/internal/text/shaper.h>
+#include <dali-toolkit/internal/text/text-run-container.h>
 
 namespace
 {
@@ -313,6 +314,381 @@ bool Controller::Impl::ProcessInputEvents()
   return decoratorUpdated;
 }
 
+void Controller::Impl::CalculateTextUpdateIndices( Length& numberOfCharacters )
+{
+  mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+  mTextUpdateInfo.mStartGlyphIndex = 0u;
+  mTextUpdateInfo.mStartLineIndex = 0u;
+  numberOfCharacters = 0u;
+
+  const Length numberOfParagraphs = mLogicalModel->mParagraphInfo.Count();
+  if( 0u == numberOfParagraphs )
+  {
+    mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+    numberOfCharacters = 0u;
+
+    mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
+
+    // Nothing else to do if there are no paragraphs.
+    return;
+  }
+
+  // Find the paragraphs to be updated.
+  Vector<ParagraphRunIndex> paragraphsToBeUpdated;
+  if( mTextUpdateInfo.mCharacterIndex >= mTextUpdateInfo.mPreviousNumberOfCharacters )
+  {
+    // Text is being added at the end of the current text.
+    if( mTextUpdateInfo.mIsLastCharacterNewParagraph )
+    {
+      // Text is being added in a new paragraph after the last character of the text.
+      mTextUpdateInfo.mParagraphCharacterIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
+      numberOfCharacters = 0u;
+      mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
+
+      mTextUpdateInfo.mStartGlyphIndex = mVisualModel->mGlyphs.Count();
+      mTextUpdateInfo.mStartLineIndex = mVisualModel->mLines.Count() - 1u;
+
+      // Nothing else to do;
+      return;
+    }
+
+    paragraphsToBeUpdated.PushBack( numberOfParagraphs - 1u );
+  }
+  else
+  {
+    CharacterIndex lastIndex = 0u;
+    if( mTextUpdateInfo.mFullRelayoutNeeded )
+    {
+      lastIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
+    }
+    else
+    {
+      lastIndex = ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
+    }
+    mLogicalModel->FindParagraphs( mTextUpdateInfo.mCharacterIndex,
+                                   lastIndex,
+                                   paragraphsToBeUpdated );
+  }
+
+  if( 0u != paragraphsToBeUpdated.Count() )
+  {
+    const ParagraphRunIndex firstParagraphIndex = *( paragraphsToBeUpdated.Begin() );
+    const ParagraphRun& firstParagraph = *( mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex );
+    mTextUpdateInfo.mParagraphCharacterIndex = firstParagraph.characterRun.characterIndex;
+
+    ParagraphRunIndex lastParagraphIndex = *( paragraphsToBeUpdated.End() - 1u );
+    const ParagraphRun& lastParagraph = *( mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex );
+
+    if( ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) &&                                            // Some character are removed.
+        ( lastParagraphIndex < numberOfParagraphs - 1u ) &&                                                // There is a next paragraph.
+        ( ( lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters ) == // The last removed character is the new paragraph character.
+          ( mTextUpdateInfo.mCharacterIndex + mTextUpdateInfo.mNumberOfCharactersToRemove ) ) )
+    {
+      // The new paragraph character of the last updated paragraph has been removed so is going to be merged with the next one.
+      const ParagraphRun& lastParagraph = *( mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex + 1u );
+
+      numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
+    }
+    else
+    {
+      numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
+    }
+  }
+  mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
+  mTextUpdateInfo.mStartGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex );
+}
+
+void Controller::Impl::ClearFullModelData( OperationsMask operations )
+{
+  if( GET_LINE_BREAKS & operations )
+  {
+    mLogicalModel->mLineBreakInfo.Clear();
+    mLogicalModel->mParagraphInfo.Clear();
+  }
+
+  if( GET_WORD_BREAKS & operations )
+  {
+    mLogicalModel->mLineBreakInfo.Clear();
+  }
+
+  if( GET_SCRIPTS & operations )
+  {
+    mLogicalModel->mScriptRuns.Clear();
+  }
+
+  if( VALIDATE_FONTS & operations )
+  {
+    mLogicalModel->mFontRuns.Clear();
+  }
+
+  if( 0u != mLogicalModel->mBidirectionalParagraphInfo.Count() )
+  {
+    if( BIDI_INFO & operations )
+    {
+      mLogicalModel->mBidirectionalParagraphInfo.Clear();
+      mLogicalModel->mCharacterDirections.Clear();
+    }
+
+    if( REORDER & operations )
+    {
+      // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+      for( Vector<BidirectionalLineInfoRun>::Iterator it = mLogicalModel->mBidirectionalLineInfo.Begin(),
+             endIt = mLogicalModel->mBidirectionalLineInfo.End();
+           it != endIt;
+           ++it )
+      {
+        BidirectionalLineInfoRun& bidiLineInfo = *it;
+
+        free( bidiLineInfo.visualToLogicalMap );
+        bidiLineInfo.visualToLogicalMap = NULL;
+      }
+      mLogicalModel->mBidirectionalLineInfo.Clear();
+
+      mLogicalModel->mLogicalToVisualMap.Clear();
+      mLogicalModel->mVisualToLogicalMap.Clear();
+    }
+  }
+
+  if( SHAPE_TEXT & operations )
+  {
+    mVisualModel->mGlyphs.Clear();
+    mVisualModel->mGlyphsToCharacters.Clear();
+    mVisualModel->mCharactersToGlyph.Clear();
+    mVisualModel->mCharactersPerGlyph.Clear();
+    mVisualModel->mGlyphsPerCharacter.Clear();
+    mVisualModel->mGlyphPositions.Clear();
+  }
+
+  if( LAYOUT & operations )
+  {
+    mVisualModel->mLines.Clear();
+  }
+}
+
+void Controller::Impl::ClearCharacterModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
+{
+  const CharacterIndex endIndexPlusOne = endIndex + 1u;
+
+  if( GET_LINE_BREAKS & operations )
+  {
+    // Clear the line break info.
+    LineBreakInfo* lineBreakInfoBuffer = mLogicalModel->mLineBreakInfo.Begin();
+
+    mLogicalModel->mLineBreakInfo.Erase( lineBreakInfoBuffer + startIndex,
+                                         lineBreakInfoBuffer + endIndexPlusOne );
+
+    // Clear the paragraphs.
+    ClearCharacterRuns( startIndex,
+                        endIndex,
+                        mLogicalModel->mParagraphInfo );
+  }
+
+  if( GET_WORD_BREAKS & operations )
+  {
+    // Clear the word break info.
+    WordBreakInfo* wordBreakInfoBuffer = mLogicalModel->mWordBreakInfo.Begin();
+
+    mLogicalModel->mWordBreakInfo.Erase( wordBreakInfoBuffer + startIndex,
+                                         wordBreakInfoBuffer + endIndexPlusOne );
+  }
+
+  if( GET_SCRIPTS & operations )
+  {
+    // Clear the scripts.
+    ClearCharacterRuns( startIndex,
+                        endIndex,
+                        mLogicalModel->mScriptRuns );
+  }
+
+  if( VALIDATE_FONTS & operations )
+  {
+    // Clear the fonts.
+    ClearCharacterRuns( startIndex,
+                        endIndex,
+                        mLogicalModel->mFontRuns );
+  }
+
+  if( 0u != mLogicalModel->mBidirectionalParagraphInfo.Count() )
+  {
+    if( BIDI_INFO & operations )
+    {
+      // Clear the bidirectional paragraph info.
+      ClearCharacterRuns( startIndex,
+                          endIndex,
+                          mLogicalModel->mBidirectionalParagraphInfo );
+
+      // Clear the character's directions.
+      CharacterDirection* characterDirectionsBuffer = mLogicalModel->mCharacterDirections.Begin();
+
+      mLogicalModel->mCharacterDirections.Erase( characterDirectionsBuffer + startIndex,
+                                                 characterDirectionsBuffer + endIndexPlusOne );
+    }
+
+    if( REORDER & operations )
+    {
+      uint32_t startRemoveIndex = mLogicalModel->mBidirectionalLineInfo.Count();
+      uint32_t endRemoveIndex = startRemoveIndex;
+      ClearCharacterRuns( startIndex,
+                          endIndex,
+                          mLogicalModel->mBidirectionalLineInfo,
+                          startRemoveIndex,
+                          endRemoveIndex );
+
+      BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mLogicalModel->mBidirectionalLineInfo.Begin();
+
+      // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+      for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfoBuffer + startRemoveIndex,
+             endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
+           it != endIt;
+           ++it )
+      {
+        BidirectionalLineInfoRun& bidiLineInfo = *it;
+
+        free( bidiLineInfo.visualToLogicalMap );
+        bidiLineInfo.visualToLogicalMap = NULL;
+      }
+
+      mLogicalModel->mBidirectionalLineInfo.Erase( bidirectionalLineInfoBuffer + startRemoveIndex,
+                                                   bidirectionalLineInfoBuffer + endRemoveIndex );
+
+      // Clear the logical to visual and the visual to logical conversion tables.
+      CharacterIndex* logicalToVisualMapBuffer = mLogicalModel->mLogicalToVisualMap.Begin();
+      mLogicalModel->mLogicalToVisualMap.Erase( logicalToVisualMapBuffer + startIndex,
+                                                logicalToVisualMapBuffer + endIndexPlusOne );
+
+      CharacterIndex* visualToLogicalMapBuffer = mLogicalModel->mVisualToLogicalMap.Begin();
+      mLogicalModel->mVisualToLogicalMap.Erase( visualToLogicalMapBuffer + startIndex,
+                                                visualToLogicalMapBuffer + endIndexPlusOne );
+    }
+  }
+}
+
+void Controller::Impl::ClearGlyphModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
+{
+  const CharacterIndex endIndexPlusOne = endIndex + 1u;
+  const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex;
+
+  const bool clearShape = SHAPE_TEXT & operations;
+  const bool clearLayout = LAYOUT & operations;
+
+  if( clearShape || clearLayout )
+  {
+    // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
+    GlyphIndex* charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
+    Length* glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
+
+    const GlyphIndex endGlyphIndex = *( charactersToGlyphBuffer + endIndex );
+    const GlyphIndex endGlyphIndexPlusOne = endGlyphIndex + *( glyphsPerCharacterBuffer + endIndex );
+    const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
+
+    if( clearShape )
+    {
+      // Update the character to glyph indices.
+      for( Vector<GlyphIndex>::Iterator it =  charactersToGlyphBuffer + endIndexPlusOne,
+             endIt =  charactersToGlyphBuffer + mVisualModel->mCharactersToGlyph.Count();
+           it != endIt;
+           ++it )
+      {
+        CharacterIndex& index = *it;
+        index -= numberOfGlyphsRemoved;
+      }
+
+      // Clear the character to glyph conversion table.
+      mVisualModel->mCharactersToGlyph.Erase( charactersToGlyphBuffer + startIndex,
+                                              charactersToGlyphBuffer + endIndexPlusOne );
+
+      // Clear the glyphs per character table.
+      mVisualModel->mGlyphsPerCharacter.Erase( glyphsPerCharacterBuffer + startIndex,
+                                               glyphsPerCharacterBuffer + endIndexPlusOne );
+
+      // Clear the glyphs buffer.
+      GlyphInfo* glyphsBuffer = mVisualModel->mGlyphs.Begin();
+      mVisualModel->mGlyphs.Erase( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                   glyphsBuffer + endGlyphIndexPlusOne );
+
+      CharacterIndex* glyphsToCharactersBuffer = mVisualModel->mGlyphsToCharacters.Begin();
+
+      // Update the glyph to character indices.
+      for( Vector<CharacterIndex>::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
+             endIt = glyphsToCharactersBuffer + mVisualModel->mGlyphsToCharacters.Count();
+           it != endIt;
+           ++it )
+      {
+        CharacterIndex& index = *it;
+        index -= numberOfCharactersRemoved;
+      }
+
+      // Clear the glyphs to characters buffer.
+      mVisualModel->mGlyphsToCharacters.Erase( glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                               glyphsToCharactersBuffer  + endGlyphIndexPlusOne );
+
+      // Clear the characters per glyph buffer.
+      Length* charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
+      mVisualModel->mCharactersPerGlyph.Erase( charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                               charactersPerGlyphBuffer + endGlyphIndexPlusOne );
+
+      // Clear the positions buffer.
+      Vector2* positionsBuffer = mVisualModel->mGlyphPositions.Begin();
+      mVisualModel->mGlyphPositions.Erase( positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                           positionsBuffer + endGlyphIndexPlusOne );
+    }
+
+    if( clearLayout )
+    {
+      // Clear the lines.
+      uint32_t startRemoveIndex = mVisualModel->mLines.Count();
+      uint32_t endRemoveIndex = startRemoveIndex;
+      ClearCharacterRuns( startIndex,
+                          endIndex,
+                          mVisualModel->mLines,
+                          startRemoveIndex,
+                          endRemoveIndex );
+
+      // Will update the glyph runs.
+      uint32_t startRemoveGlyphIndex = mVisualModel->mLines.Count();
+      uint32_t endRemoveGlyphIndex = startRemoveIndex;
+      ClearGlyphRuns( mTextUpdateInfo.mStartGlyphIndex,
+                      endGlyphIndex,
+                      mVisualModel->mLines,
+                      startRemoveGlyphIndex,
+                      endRemoveGlyphIndex );
+
+      // Set the line index from where to insert the new laid-out lines.
+      mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
+
+      LineRun* linesBuffer = mVisualModel->mLines.Begin();
+      mVisualModel->mLines.Erase( linesBuffer + startRemoveIndex,
+                                  linesBuffer + endRemoveIndex );
+    }
+  }
+}
+
+void Controller::Impl::ClearModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
+{
+  if( mTextUpdateInfo.mClearAll ||
+      ( ( 0u == startIndex ) &&
+        ( mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u ) ) )
+  {
+    ClearFullModelData( operations );
+  }
+  else
+  {
+    // Clear the model data related with characters.
+    ClearCharacterModelData( startIndex, endIndex, operations );
+
+    // Clear the model data related with glyphs.
+    ClearGlyphModelData( startIndex, endIndex, operations );
+  }
+
+  // The estimated number of lines. Used to avoid reallocations when layouting.
+  mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mVisualModel->mLines.Count(), mLogicalModel->mParagraphInfo.Count() );
+
+  mVisualModel->ClearCaches();
+
+  // TODO finish the mark-up.
+  mVisualModel->mColorRuns.Clear();
+}
+
 void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
 {
   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel\n" );
@@ -320,13 +696,35 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
   // Calculate the operations to be done.
   const OperationsMask operations = static_cast<OperationsMask>( mOperationsPending & operationsRequired );
 
+  if( NO_OPERATION == operations )
+  {
+    // Nothing to do if no operations are pending and required.
+    return;
+  }
+
   Vector<Character>& utf32Characters = mLogicalModel->mText;
 
   const Length numberOfCharacters = utf32Characters.Count();
 
-  Vector<LineBreakInfo>& lineBreakInfo = mLogicalModel->mLineBreakInfo;
+  // Index to the first character of the first paragraph to be updated.
   CharacterIndex startIndex = 0u;
-  Length requestedNumberOfCharacters = numberOfCharacters;
+  // Number of characters of the paragraphs to be removed.
+  Length paragraphCharacters = 0u;
+
+  CalculateTextUpdateIndices( paragraphCharacters );
+  startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
+
+  if( mTextUpdateInfo.mClearAll ||
+      ( 0u != paragraphCharacters ) )
+  {
+    ClearModelData( startIndex, startIndex + ( ( paragraphCharacters > 0u ) ? paragraphCharacters - 1u : 0u ), operationsRequired );
+  }
+
+  mTextUpdateInfo.mClearAll = false;
+
+  Vector<LineBreakInfo>& lineBreakInfo = mLogicalModel->mLineBreakInfo;
+  const Length requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
+
   if( GET_LINE_BREAKS & operations )
   {
     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
@@ -400,21 +798,9 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
 
   Vector<Character> mirroredUtf32Characters;
   bool textMirrored = false;
-  Length numberOfParagraphs = 0u;
+  const Length numberOfParagraphs = mLogicalModel->mParagraphInfo.Count();
   if( BIDI_INFO & operations )
   {
-    // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
-    // bidirectional info.
-
-    const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
-    for( Length index = 0u; index < numberOfCharacters; ++index )
-    {
-      if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
-      {
-        ++numberOfParagraphs;
-      }
-    }
-
     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mLogicalModel->mBidirectionalParagraphInfo;
     bidirectionalInfo.Reserve( numberOfParagraphs );
 
@@ -459,7 +845,7 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
   Vector<GlyphIndex> newParagraphGlyphs;
   newParagraphGlyphs.Reserve( numberOfParagraphs );
 
-  GlyphIndex startGlyphIndex = 0u;
+  const Length currentNumberOfGlyphs = glyphs.Count();
   if( SHAPE_TEXT & operations )
   {
     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
@@ -469,7 +855,7 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
                scripts,
                validFonts,
                startIndex,
-               startGlyphIndex,
+               mTextUpdateInfo.mStartGlyphIndex,
                requestedNumberOfCharacters,
                glyphs,
                glyphsToCharactersMap,
@@ -477,16 +863,16 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
                newParagraphGlyphs );
 
     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
-    mVisualModel->CreateGlyphsPerCharacterTable( startIndex, startGlyphIndex, numberOfCharacters );
-    mVisualModel->CreateCharacterToGlyphTable( startIndex, startGlyphIndex, numberOfCharacters );
+    mVisualModel->CreateGlyphsPerCharacterTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
+    mVisualModel->CreateCharacterToGlyphTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
   }
 
-  const Length numberOfGlyphs = glyphs.Count();
+  const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
 
   if( GET_GLYPH_METRICS & operations )
   {
-    GlyphInfo* glyphsBuffer = glyphs.Begin() + startGlyphIndex;
-    mMetrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
+    GlyphInfo* glyphsBuffer = glyphs.Begin();
+    mMetrics->GetGlyphMetrics( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs );
 
     // Update the width and advance of all new paragraph characters.
     for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it )
@@ -520,6 +906,12 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
     // TODO: At the moment the underline runs are only for pre-edit.
     mVisualModel->mUnderlineRuns.PushBack( underlineRun );
   }
+
+  // The estimated number of lines. Used to avoid reallocations when layouting.
+  mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mVisualModel->mLines.Count(), mLogicalModel->mParagraphInfo.Count() );
+
+  // Set the previous number of characters for the next time the text is updated.
+  mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
 }
 
 bool Controller::Impl::UpdateModelStyle( OperationsMask operationsRequired )
@@ -988,12 +1380,13 @@ void Controller::Impl::RetrieveSelection( std::string& selectedText, bool delete
   const CharacterIndex startOfSelectedText = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
   const Length lengthOfSelectedText = ( handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition ) - startOfSelectedText;
 
+  Vector<Character>& utf32Characters = mLogicalModel->mText;
+  const Length numberOfCharacters = utf32Characters.Count();
+
   // Validate the start and end selection points
-  if( ( startOfSelectedText + lengthOfSelectedText ) <= mLogicalModel->mText.Count() )
+  if( ( startOfSelectedText + lengthOfSelectedText ) <= numberOfCharacters )
   {
     //Get text as a UTF8 string
-    Vector<Character>& utf32Characters = mLogicalModel->mText;
-
     Utf32ToUtf8( &utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText );
 
     if( deleteAfterRetrieval ) // Only delete text if copied successfully
@@ -1003,12 +1396,14 @@ void Controller::Impl::RetrieveSelection( std::string& selectedText, bool delete
 
       mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
 
-      // Delete text between handles
-      Vector<Character>& currentText = mLogicalModel->mText;
+      // Mark the paragraphs to be updated.
+      mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+      mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
 
-      Vector<Character>::Iterator first = currentText.Begin() + startOfSelectedText;
+      // Delete text between handles
+      Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
       Vector<Character>::Iterator last  = first + lengthOfSelectedText;
-      currentText.Erase( first, last );
+      utf32Characters.Erase( first, last );
 
       // Scroll after delete.
       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
index f88ca8d..2f14702 100644 (file)
@@ -223,6 +223,63 @@ struct FontDefaults
   bool   sizeDefined:1; ///< Whether the default font's point size is defined.
 };
 
+/**
+ * @brief Stores indices used to update the text.
+ * Stores the character index where the text is updated and the number of characters removed and added.
+ * Stores as well indices to the first and the last paragraphs to be updated.
+ */
+struct TextUpdateInfo
+{
+  TextUpdateInfo()
+  : mCharacterIndex( 0u ),
+    mNumberOfCharactersToRemove( 0u ),
+    mNumberOfCharactersToAdd( 0u ),
+    mPreviousNumberOfCharacters( 0u ),
+    mParagraphCharacterIndex( 0u ),
+    mRequestedNumberOfCharacters( 0u ),
+    mStartGlyphIndex( 0u ),
+    mStartLineIndex( 0u ),
+    mEstimatedNumberOfLines( 0u ),
+    mClearAll( true ),
+    mFullRelayoutNeeded( true ),
+    mIsLastCharacterNewParagraph( false )
+  {}
+
+  ~TextUpdateInfo()
+  {}
+
+  CharacterIndex    mCharacterIndex;                ///< Index to the first character to be updated.
+  Length            mNumberOfCharactersToRemove;    ///< The number of characters to be removed.
+  Length            mNumberOfCharactersToAdd;       ///< The number of characters to be added.
+  Length            mPreviousNumberOfCharacters;    ///< The number of characters before the text update.
+
+  CharacterIndex    mParagraphCharacterIndex;       ///< Index of the first character of the first paragraph to be updated.
+  Length            mRequestedNumberOfCharacters;   ///< The requested number of characters.
+  GlyphIndex        mStartGlyphIndex;
+  LineIndex         mStartLineIndex;
+  Length            mEstimatedNumberOfLines;         ///< The estimated number of lines. Used to avoid reallocations when layouting.
+
+  bool              mClearAll:1;                    ///< Whether the whole text is cleared. i.e. when the text is reset.
+  bool              mFullRelayoutNeeded:1;          ///< Whether a full re-layout is needed. i.e. when a new size is set to the text control.
+  bool              mIsLastCharacterNewParagraph:1; ///< Whether the last character is a new paragraph character.
+
+  void Clear()
+  {
+    // Clear all info except the mPreviousNumberOfCharacters member.
+    mCharacterIndex = static_cast<CharacterIndex>( -1 );
+    mNumberOfCharactersToRemove = 0u;
+    mNumberOfCharactersToAdd = 0u;
+    mParagraphCharacterIndex = 0u;
+    mRequestedNumberOfCharacters = 0u;
+    mStartGlyphIndex = 0u;
+    mStartLineIndex = 0u;
+    mEstimatedNumberOfLines = 0u;
+    mClearAll = false;
+    mFullRelayoutNeeded = false;
+    mIsLastCharacterNewParagraph = false;
+  }
+};
+
 struct Controller::Impl
 {
   Impl( ControlInterface& controlInterface )
@@ -239,6 +296,7 @@ struct Controller::Impl
     mModifyEvents(),
     mTextColor( Color::BLACK ),
     mAlignmentOffset(),
+    mTextUpdateInfo(),
     mOperationsPending( NO_OPERATION ),
     mMaximumNumberOfCharacters( 50u ),
     mRecalculateNaturalSize( true ),
@@ -367,10 +425,59 @@ struct Controller::Impl
   bool IsClipboardEmpty()
   {
     bool result( mClipboard && mClipboard.NumberOfItems() );
-    return !result; // // If NumberOfItems greater than 0, return false
+    return !result; // If NumberOfItems greater than 0, return false
   }
 
   /**
+   * @brief Calculates the start character index of the first paragraph to be updated and
+   * the end character index of the last paragraph to be updated.
+   *
+   * @param[out] numberOfCharacters The number of characters to be updated.
+   */
+  void CalculateTextUpdateIndices( Length& numberOfCharacters );
+
+  /**
+   * @brief Helper to clear completely the parts of the model specified by the given @p operations.
+   *
+   * @note It never clears the text stored in utf32.
+   */
+  void ClearFullModelData( OperationsMask operations );
+
+  /**
+   * @brief Helper to clear completely the parts of the model related with the characters specified by the given @p operations.
+   *
+   * @note It never clears the text stored in utf32.
+   *
+   * @param[in] startIndex Index to the first character to be cleared.
+   * @param[in] endIndex Index to the last character to be cleared.
+   * @param[in] operations The operations required.
+   */
+  void ClearCharacterModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations );
+
+  /**
+   * @brief Helper to clear completely the parts of the model related with the glyphs specified by the given @p operations.
+   *
+   * @note It never clears the text stored in utf32.
+   * @note Character indices are transformed to glyph indices.
+   *
+   * @param[in] startIndex Index to the first character to be cleared.
+   * @param[in] endIndex Index to the last character to be cleared.
+   * @param[in] operations The operations required.
+   */
+  void ClearGlyphModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations );
+
+  /**
+   * @brief Helper to clear the parts of the model specified by the given @p operations and from @p startIndex to @p endIndex.
+   *
+   * @note It never clears the text stored in utf32.
+   *
+   * @param[in] startIndex Index to the first character to be cleared.
+   * @param[in] endIndex Index to the last character to be cleared.
+   * @param[in] operations The operations required.
+   */
+  void ClearModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations );
+
+  /**
    * @brief Updates the logical and visual models.
    *
    * When text or style changes the model is set with some operations pending.
@@ -541,6 +648,7 @@ struct Controller::Impl
   Vector<ModifyEvent> mModifyEvents;       ///< Temporary stores the text set until the next relayout.
   Vector4 mTextColor;                      ///< The regular text color
   Vector2 mAlignmentOffset;                ///< Vertical and horizontal offset of the whole text inside the control due to alignment.
+  TextUpdateInfo mTextUpdateInfo;          ///< Info of the characters updated.
   OperationsMask mOperationsPending;       ///< Operations pending to be done to layout the text.
   Length mMaximumNumberOfCharacters;       ///< Maximum number of characters that can be inserted.
 
index f477c15..b32b20e 100644 (file)
@@ -193,6 +193,9 @@ void Controller::SetText( const std::string& text )
     DALI_ASSERT_DEBUG( textSize >= characterCount && "Invalid UTF32 conversion length" );
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, textSize, mImpl->mLogicalModel->mText.Count() );
 
+    // The characters to be added.
+    mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mLogicalModel->mText.Count();
+
     // To reset the cursor position
     lastCursorIndex = characterCount;
 
@@ -544,8 +547,12 @@ bool Controller::RemoveText( int cursorOffset, int numberOfCharacters )
       numberOfCharacters = currentText.Count() - cursorIndex;
     }
 
-    if( ( cursorIndex + numberOfCharacters ) <= currentText.Count() )
+    if( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters )
     {
+      // Mark the paragraphs to be updated.
+      mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
+
       // Update the input style and remove the text's style before removing the text.
 
       // Set first the default input style.
@@ -977,20 +984,28 @@ Vector3 Controller::GetNaturalSize()
     // Make sure the model is up-to-date before layouting
     mImpl->UpdateModel( onlyOnceOperations );
 
-    // Operations that need to be done if the size changes.
-    const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
-                                                                        ALIGN  |
-                                                                        REORDER );
+    // Layout the text for the new width.
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
+
+    // Set the update info to relayout the whole text.
+    mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+    mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
+
+    // Store the actual control's width.
+    const float actualControlWidth = mImpl->mVisualModel->mControlSize.width;
 
     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
                 static_cast<OperationsMask>( onlyOnceOperations |
-                                             sizeOperations ),
+                                             LAYOUT ),
                 naturalSize.GetVectorXY() );
 
     // Do not do again the only once operations.
     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
 
     // Do the size related operations again.
+    const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
+                                                                        ALIGN  |
+                                                                        REORDER );
     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
 
     // Stores the natural size to avoid recalculate it again
@@ -999,6 +1014,12 @@ Vector3 Controller::GetNaturalSize()
 
     mImpl->mRecalculateNaturalSize = false;
 
+    // Clear the update info. This info will be set the next time the text is updated.
+    mImpl->mTextUpdateInfo.Clear();
+
+    // Restore the actual control's width.
+    mImpl->mVisualModel->mControlSize.width = actualControlWidth;
+
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
   }
   else
@@ -1035,21 +1056,38 @@ float Controller::GetHeightForWidth( float width )
     // Make sure the model is up-to-date before layouting
     mImpl->UpdateModel( onlyOnceOperations );
 
-    // Operations that need to be done if the size changes.
-    const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
-                                                                        ALIGN  |
-                                                                        REORDER );
+
+    // Layout the text for the new width.
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
+
+    // Set the update info to relayout the whole text.
+    mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+    mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
+
+    // Store the actual control's width.
+    const float actualControlWidth = mImpl->mVisualModel->mControlSize.width;
 
     DoRelayout( Size( width, MAX_FLOAT ),
                 static_cast<OperationsMask>( onlyOnceOperations |
-                                             sizeOperations ),
+                                             LAYOUT ),
                 layoutSize );
 
     // Do not do again the only once operations.
     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
 
     // Do the size related operations again.
+    const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
+                                                                        ALIGN  |
+                                                                        REORDER );
+
     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
+
+    // Clear the update info. This info will be set the next time the text is updated.
+    mImpl->mTextUpdateInfo.Clear();
+
+    // Restore the actual control's width.
+    mImpl->mVisualModel->mControlSize.width = actualControlWidth;
+
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
   }
   else
@@ -1073,6 +1111,10 @@ bool Controller::Relayout( const Size& size )
       mImpl->mVisualModel->mGlyphPositions.Clear();
       glyphsRemoved = true;
     }
+
+    // Clear the update info. This info will be set the next time the text is updated.
+    mImpl->mTextUpdateInfo.Clear();
+
     // Not worth to relayout if width or height is equal to zero.
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
     return glyphsRemoved;
@@ -1091,8 +1133,9 @@ bool Controller::Relayout( const Size& size )
                                                              ALIGN                     |
                                                              UPDATE_ACTUAL_SIZE        |
                                                              REORDER );
-
-    mImpl->mVisualModel->mControlSize = size;
+    // Set the update info to relayout the whole text.
+    mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
+    mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
   }
 
   // Whether there are modify events.
@@ -1114,7 +1157,7 @@ bool Controller::Relayout( const Size& size )
 
   // Layout the text.
   Size layoutSize;
-  updated = DoRelayout( mImpl->mVisualModel->mControlSize,
+  updated = DoRelayout( size,
                         mImpl->mOperationsPending,
                         layoutSize ) || updated;
 
@@ -1149,6 +1192,9 @@ bool Controller::Relayout( const Size& size )
     updated = mImpl->ProcessInputEvents() || updated;
   }
 
+  // Clear the update info. This info will be set the next time the text is updated.
+  mImpl->mTextUpdateInfo.Clear();
+
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
   return updated;
 }
@@ -1205,11 +1251,17 @@ void Controller::ResetText()
 {
   // Reset buffers.
   mImpl->mLogicalModel->mText.Clear();
-  ClearModelData();
 
   // We have cleared everything including the placeholder-text
   mImpl->PlaceholderCleared();
 
+  mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
+  mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+  mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
+
+  // Clear any previous text.
+  mImpl->mTextUpdateInfo.mClearAll = true;
+
   // The natural size needs to be re-calculated.
   mImpl->mRecalculateNaturalSize = true;
 
@@ -1244,19 +1296,11 @@ void Controller::ResetScrollPosition()
 
 void Controller::TextReplacedEvent()
 {
-  // Reset buffers.
-  ClearModelData();
-
   // The natural size needs to be re-calculated.
   mImpl->mRecalculateNaturalSize = true;
 
   // Apply modifications to the model
   mImpl->mOperationsPending = ALL_OPERATIONS;
-  mImpl->UpdateModel( ALL_OPERATIONS );
-  mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
-                                                           ALIGN              |
-                                                           UPDATE_ACTUAL_SIZE |
-                                                           REORDER );
 }
 
 void Controller::TextInsertedEvent()
@@ -1268,19 +1312,11 @@ void Controller::TextInsertedEvent()
     return;
   }
 
-  // TODO - Optimize this
-  ClearModelData();
-
   // The natural size needs to be re-calculated.
   mImpl->mRecalculateNaturalSize = true;
 
   // Apply modifications to the model; TODO - Optimize this
   mImpl->mOperationsPending = ALL_OPERATIONS;
-  mImpl->UpdateModel( ALL_OPERATIONS );
-  mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
-                                                           ALIGN              |
-                                                           UPDATE_ACTUAL_SIZE |
-                                                           REORDER );
 
   // Queue a cursor reposition event; this must wait until after DoRelayout()
   if( EventData::IsEditingState( mImpl->mEventData->mState ) )
@@ -1299,19 +1335,11 @@ void Controller::TextDeletedEvent()
     return;
   }
 
-  // TODO - Optimize this
-  ClearModelData();
-
   // The natural size needs to be re-calculated.
   mImpl->mRecalculateNaturalSize = true;
 
   // Apply modifications to the model; TODO - Optimize this
   mImpl->mOperationsPending = ALL_OPERATIONS;
-  mImpl->UpdateModel( ALL_OPERATIONS );
-  mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
-                                                           ALIGN              |
-                                                           UPDATE_ACTUAL_SIZE |
-                                                           REORDER );
 
   // Queue a cursor reposition event; this must wait until after DoRelayout()
   mImpl->mEventData->mUpdateCursorPosition = true;
@@ -1331,15 +1359,27 @@ bool Controller::DoRelayout( const Size& size,
   // Calculate the operations to be done.
   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
 
+  const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
+  const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
+
   if( LAYOUT & operations )
   {
     // Some vectors with data needed to layout and reorder may be void
     // after the first time the text has been laid out.
     // Fill the vectors again.
 
-    const Length numberOfGlyphs = mImpl->mVisualModel->mGlyphs.Count();
+    // Calculate the number of glyphs to layout.
+    const Vector<GlyphIndex>& charactersToGlyph = mImpl->mVisualModel->mCharactersToGlyph;
+    const Vector<Length>& glyphsPerCharacter = mImpl->mVisualModel->mGlyphsPerCharacter;
+    const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
+    const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
 
-    if( 0u == numberOfGlyphs )
+    const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
+    const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
+    const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
+    const Length totalNumberOfGlyphs = mImpl->mVisualModel->mGlyphs.Count();
+
+    if( 0u == totalNumberOfGlyphs )
     {
       if( UPDATE_ACTUAL_SIZE & operations )
       {
@@ -1358,8 +1398,6 @@ bool Controller::DoRelayout( const Size& size,
     const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
     const Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
     const Character* const textBuffer = mImpl->mLogicalModel->mText.Begin();
-    const Vector<GlyphIndex>& charactersToGlyph = mImpl->mVisualModel->mCharactersToGlyph;
-    const Vector<Length>& glyphsPerCharacter = mImpl->mVisualModel->mGlyphsPerCharacter;
 
     // Set the layout parameters.
     LayoutParameters layoutParameters( size,
@@ -1370,37 +1408,28 @@ bool Controller::DoRelayout( const Size& size,
                                        glyphs.Begin(),
                                        glyphsToCharactersMap.Begin(),
                                        charactersPerGlyph.Begin(),
-                                       charactersToGlyph.Begin(),
-                                       glyphsPerCharacter.Begin(),
-                                       numberOfGlyphs );
-
-    // The laid-out lines.
-    // It's not possible to know in how many lines the text is going to be laid-out,
-    // but it can be resized at least with the number of 'paragraphs' to avoid
-    // some re-allocations.
-    Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
-
-    // Delete any previous laid out lines before setting the new ones.
-    lines.Clear();
-
-    // The capacity of the bidirectional paragraph info is the number of paragraphs.
-    lines.Reserve( mImpl->mLogicalModel->mBidirectionalParagraphInfo.Capacity() );
+                                       charactersToGlyphBuffer,
+                                       glyphsPerCharacterBuffer,
+                                       totalNumberOfGlyphs );
 
     // Resize the vector of positions to have the same size than the vector of glyphs.
     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
-    glyphPositions.Resize( numberOfGlyphs );
+    glyphPositions.Resize( totalNumberOfGlyphs );
 
     // Whether the last character is a new paragraph character.
-    layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mLogicalModel->mText.Count() - 1u ) ) );
+    mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mLogicalModel->mText.Count() - 1u ) ) );
+    layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
 
     // The initial glyph and the number of glyphs to layout.
-    layoutParameters.startGlyphIndex = 0u;
+    layoutParameters.startGlyphIndex = startGlyphIndex;
     layoutParameters.numberOfGlyphs = numberOfGlyphs;
+    layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
+    layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
 
     // Update the visual model.
     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
                                                    glyphPositions,
-                                                   lines,
+                                                   mImpl->mVisualModel->mLines,
                                                    layoutSize );
 
     if( viewUpdated )
@@ -1416,26 +1445,28 @@ bool Controller::DoRelayout( const Size& size,
         {
           // Get the lines
           const Length numberOfLines = mImpl->mVisualModel->mLines.Count();
-          const CharacterIndex startIndex = 0u;
-          const Length requestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
 
           // Reorder the lines.
           bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
           ReorderLines( bidirectionalInfo,
                         startIndex,
                         requestedNumberOfCharacters,
-                        lines,
+                        mImpl->mVisualModel->mLines,
                         bidirectionalLineInfo );
 
           // Set the bidirectional info per line into the layout parameters.
           layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
           layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
 
+          // TODO: update the conversion map instead creating it from scratch.
+          //       Note this tables store indices to characters, so update the table means modify all the indices of the text after the last updated character.
+          //       It's better to refactor this. Store this table per line and don't update the indices.
+          //       For the cursor position probably is better to use the function instead creating a table.
           // Set the bidirectional info into the model.
           mImpl->mLogicalModel->SetVisualToLogicalMap( layoutParameters.lineBidirectionalInfoRunsBuffer,
                                                        layoutParameters.numberOfBidirectionalInfoRuns,
-                                                       startIndex,
-                                                       requestedNumberOfCharacters );
+                                                       0u,
+                                                       mImpl->mLogicalModel->mText.Count() );
 
           // Re-layout the text. Reorder those lines with right to left characters.
           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
@@ -1443,19 +1474,6 @@ bool Controller::DoRelayout( const Size& size,
                                                          requestedNumberOfCharacters,
                                                          glyphPositions );
 
-          // Free the allocated memory used to store the conversion table in the bidirectional line info run.
-          for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfo.Begin(),
-                 endIt = bidirectionalLineInfo.End();
-               it != endIt;
-               ++it )
-          {
-            BidirectionalLineInfoRun& bidiLineInfo = *it;
-
-            free( bidiLineInfo.visualToLogicalMap );
-            bidiLineInfo.visualToLogicalMap = NULL;
-          }
-
-          bidirectionalLineInfo.Clear();
         }
       } // REORDER
 
@@ -1465,6 +1483,9 @@ bool Controller::DoRelayout( const Size& size,
         mImpl->mVisualModel->SetLayoutSize( layoutSize );
       }
     } // view updated
+
+    // Store the size used to layout the text.
+    mImpl->mVisualModel->mControlSize = size;
   }
   else
   {
@@ -1476,9 +1497,6 @@ bool Controller::DoRelayout( const Size& size,
     // The laid-out lines.
     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
 
-    const CharacterIndex startIndex = 0u;
-    const Length requestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
-
     mImpl->mLayoutEngine.Align( size,
                                 startIndex,
                                 requestedNumberOfCharacters,
@@ -1958,6 +1976,11 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
     }
 
+    // Mark the first paragraph to be updated.
+    mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
+    mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
+
+    // Update the cursor index.
     cursorIndex += maxSizeOfNewText;
 
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition );
@@ -2514,9 +2537,11 @@ void Controller::ShowPlaceholderText()
       size = mImpl->mEventData->mPlaceholderTextInactive.size();
     }
 
+    mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
+    mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+
     // Reset model for showing placeholder.
     mImpl->mLogicalModel->mText.Clear();
-    ClearModelData();
     mImpl->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
 
     // Convert text into UTF-32
@@ -2531,6 +2556,9 @@ void Controller::ShowPlaceholderText()
     const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
     utf32Characters.Resize( characterCount );
 
+    // The characters to be added.
+    mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
+
     // Reset the cursor position
     mImpl->mEventData->mPrimaryCursorPosition = 0;
 
@@ -2545,29 +2573,6 @@ void Controller::ShowPlaceholderText()
   }
 }
 
-void Controller::ClearModelData()
-{
-  // n.b. This does not Clear the mText from mLogicalModel
-  mImpl->mLogicalModel->mScriptRuns.Clear();
-  mImpl->mLogicalModel->mFontRuns.Clear();
-  mImpl->mLogicalModel->mLineBreakInfo.Clear();
-  mImpl->mLogicalModel->mWordBreakInfo.Clear();
-  mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
-  mImpl->mLogicalModel->mCharacterDirections.Clear();
-  mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
-  mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
-  mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
-  mImpl->mVisualModel->mGlyphs.Clear();
-  mImpl->mVisualModel->mGlyphsToCharacters.Clear();
-  mImpl->mVisualModel->mCharactersToGlyph.Clear();
-  mImpl->mVisualModel->mCharactersPerGlyph.Clear();
-  mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
-  mImpl->mVisualModel->mGlyphPositions.Clear();
-  mImpl->mVisualModel->mLines.Clear();
-  mImpl->mVisualModel->mColorRuns.Clear();
-  mImpl->mVisualModel->ClearCaches();
-}
-
 void Controller::ClearFontData()
 {
   if( mImpl->mFontDefaults )
index 44a0257..546389c 100644 (file)
@@ -776,11 +776,6 @@ private:
   void ShowPlaceholderText();
 
   /**
-   * @brief Helper to clear all the model data except for LogicalModel::mText.
-   */
-  void ClearModelData();
-
-  /**
    * @brief Helper to clear font-specific data (only).
    */
   void ClearFontData();
index d57b2ec..130c8af 100644 (file)
@@ -181,19 +181,28 @@ Length View::GetGlyphs( GlyphInfo* glyphs,
         GlyphIndex lastGlyphIndexOfLine = line->glyphRun.glyphIndex + line->glyphRun.numberOfGlyphs - 1u;
 
         // Add the alignment offset to the glyph's position.
+
+        float penY = line->ascender;
         for( Length index = 0u; index < numberOfLaidOutGlyphs; ++index )
         {
-          ( *( glyphPositions + index ) ).x += line->alignmentOffset;
+          Vector2& position =  *( glyphPositions + index );
+          position.x += line->alignmentOffset;
+          position.y += penY;
 
           if( lastGlyphIndexOfLine == index )
           {
+            penY += -line->descender;
+
             // Get the next line.
             ++lineIndex;
 
             if( lineIndex < numberOfLines )
             {
               line = lineBuffer + lineIndex;
+
               lastGlyphIndexOfLine = line->glyphRun.glyphIndex + line->glyphRun.numberOfGlyphs - 1u;
+
+              penY += line->ascender;
             }
           }
         }