[dali_2.2.3] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / controller / text-controller-relayouter.cpp
index 0d2f765..f95019a 100644 (file)
@@ -23,9 +23,9 @@
 #include <limits>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
 #include <dali-toolkit/internal/text/controller/text-controller-event-handler.h>
 #include <dali-toolkit/internal/text/controller/text-controller-impl.h>
+#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
 
 namespace
 {
@@ -86,6 +86,10 @@ Size Controller::Relayouter::CalculateLayoutSizeOnRequiredControllerSize(Control
   // Store the actual control's size to restore later.
   const Size actualControlSize = visualModel->mControlSize;
 
+  // This is to keep Index to the first character to be updated.
+  // Then restore it after calling Clear method.
+  auto updateInfoCharIndexBackup = textUpdateInfo.mCharacterIndex;
+
   // Whether the text control is editable
   const bool isEditable = NULL != impl.mEventData;
 
@@ -109,10 +113,6 @@ Size Controller::Relayouter::CalculateLayoutSizeOnRequiredControllerSize(Control
   }
   else
   {
-    // This is to keep Index to the first character to be updated.
-    // Then restore it after calling Clear method.
-    auto updateInfoCharIndexBackup = textUpdateInfo.mCharacterIndex;
-
     // Layout the text for the new width.
     // Apply the pending operations, requested operations and the only once operations.
     // Then remove onlyOnceOperations
@@ -133,16 +133,16 @@ Size Controller::Relayouter::CalculateLayoutSizeOnRequiredControllerSize(Control
     //TODO: then calculate GlyphPositions. Lines, Size, Layout for Natural-Size
     //TODO: and utilize the values in OperationsPending and TextUpdateInfo without changing the original one.
     //TODO: Also it will improve performance because there is no need todo FullRelyout on the next need for layouting.
+  }
 
-    // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
-    // By this no need to take backup and restore it.
-    textUpdateInfo.mFullRelayoutNeeded = true;
+  // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
+  // By this no need to take backup and restore it.
+  textUpdateInfo.mFullRelayoutNeeded = true;
 
-    // Restore mCharacterIndex. Because "Clear" set it to the maximum integer.
-    // The "CalculateTextUpdateIndices" does not work proprely because the mCharacterIndex will be greater than mPreviousNumberOfCharacters.
-    // Which apply an assumption to update only the last  paragraph. That could cause many of out of index crashes.
-    textUpdateInfo.mCharacterIndex = updateInfoCharIndexBackup;
-  }
+  // Restore mCharacterIndex. Because "Clear" set it to the maximum integer.
+  // The "CalculateTextUpdateIndices" does not work proprely because the mCharacterIndex will be greater than mPreviousNumberOfCharacters.
+  // Which apply an assumption to update only the last  paragraph. That could cause many of out of index crashes.
+  textUpdateInfo.mCharacterIndex = updateInfoCharIndexBackup;
 
   // Do the size related operations again.
   operationsPending = static_cast<OperationsMask>(operationsPending | sizeOperations);
@@ -253,48 +253,65 @@ void Controller::Relayouter::FitPointSizeforLayout(Controller& controller, const
     float currentFitPointSize = impl.mFontDefaults->mFitPointSize;
 
     model->mElideEnabled = false;
-    Vector<float> pointSizeArray;
 
     // check zero value
     if(pointInterval < 1.f)
     {
       impl.mTextFitStepSize = pointInterval = 1.0f;
     }
+    uint32_t pointSizeRange = static_cast<uint32_t>(ceil((maxPointSize - minPointSize) / pointInterval));
 
-    pointSizeArray.Reserve(static_cast<unsigned int>(ceil((maxPointSize - minPointSize) / pointInterval)));
-
-    for(float i = minPointSize; i < maxPointSize; i += pointInterval)
+    // Ensure minPointSize + pointSizeRange * pointInverval >= maxPointSize
+    while(minPointSize + static_cast<float>(pointSizeRange) * pointInterval < maxPointSize)
     {
-      pointSizeArray.PushBack(i);
+      ++pointSizeRange;
     }
 
-    pointSizeArray.PushBack(maxPointSize);
-
-    int bestSizeIndex = 0;
-    int min           = bestSizeIndex + 1;
-    int max           = pointSizeArray.Size() - 1;
-    while(min <= max)
+    uint32_t bestSizeIndex = 0;
+    uint32_t minIndex      = bestSizeIndex + 1u;
+    uint32_t maxIndex      = pointSizeRange + 1u;
+
+    bool bestSizeUpdatedLatest = false;
+    // Find best size as binary search.
+    // Range format as [l r). (left closed, right opened)
+    // It mean, we already check all i < l is valid, and r <= i is invalid.
+    // Below binary search will check m = (l+r)/2 point.
+    // Search area sperate as [l m) or [m+1 r)
+    //
+    // Basically, we can assume that 0 (minPointSize) is always valid.
+    // Now, we will check [1 pointSizeRange] range s.t. pointSizeRange mean the maxPointSize
+    while(minIndex < maxIndex)
     {
-      int destI = (min + max) / 2;
+      uint32_t    testIndex     = minIndex + ((maxIndex - minIndex) >> 1u);
+      const float testPointSize = std::min(maxPointSize, minPointSize + static_cast<float>(testIndex) * pointInterval);
 
-      if(CheckForTextFit(controller, pointSizeArray[destI], layoutSize))
+      if(CheckForTextFit(controller, testPointSize, layoutSize))
       {
-        bestSizeIndex = min;
-        min           = destI + 1;
+        bestSizeUpdatedLatest = true;
+
+        bestSizeIndex = testIndex;
+        minIndex      = testIndex + 1u;
       }
       else
       {
-        max           = destI - 1;
-        bestSizeIndex = max;
+        bestSizeUpdatedLatest = false;
+        maxIndex              = testIndex;
       }
     }
+    const float bestPointSize = std::min(maxPointSize, minPointSize + static_cast<float>(bestSizeIndex) * pointInterval);
+
+    // Best point size was not updated. re-run so the TextFit should be fitted really.
+    if(!bestSizeUpdatedLatest)
+    {
+      CheckForTextFit(controller, bestPointSize, layoutSize);
+    }
 
     model->mElideEnabled = actualellipsis;
-    if(currentFitPointSize != pointSizeArray[bestSizeIndex])
+    if(currentFitPointSize != bestPointSize)
     {
       impl.mTextFitChanged = true;
     }
-    impl.mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
+    impl.mFontDefaults->mFitPointSize = bestPointSize;
     impl.mFontDefaults->sizeDefined   = true;
     impl.ClearFontData();
   }