[Tizen] Fix text AutoScroll ellipsis issue 93/275993/2
authorBowon Ryu <bowon.ryu@samsung.com>
Wed, 8 Jun 2022 05:57:57 +0000 (14:57 +0900)
committerBowon Ryu <bowon.ryu@samsung.com>
Wed, 8 Jun 2022 10:12:44 +0000 (19:12 +0900)
Text should ellipsis while AutoScroll is running
when text length is bigger than MaxTextureSize.

this issue occurs as a side effect of another patch.
74f7af1b08ce65dde5959d22b2d533cbc64b9d2e

the height comparison condition is for another AutoScroll ellipsis issue
and this should not be removed.

Change-Id: I36707856c8fd1a077f2cc4f31d05678a28697b05
Signed-off-by: Bowon Ryu <bowon.ryu@samsung.com>
dali-toolkit/devel-api/text/text-utils-devel.cpp
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/text/layouts/layout-engine.cpp
dali-toolkit/internal/text/layouts/layout-engine.h
dali-toolkit/internal/text/text-controller-impl.h
dali-toolkit/internal/text/text-controller-relayouter.cpp
dali-toolkit/internal/text/text-controller-relayouter.h
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-controller.h

index e4733c1..fc402bb 100644 (file)
@@ -1051,10 +1051,12 @@ Size LayoutText(const RendererParameters& textParameters, TextAbstraction::TextR
   // Update the visual model.
   Size newLayoutSize;
   bool isAutoScrollEnabled = false;
+  bool isAutoScrollMaxTextureExceeded = false;
   layoutEngine.LayoutText(layoutParameters,
                           newLayoutSize,
                           textParameters.ellipsisEnabled,
                           isAutoScrollEnabled,
+                          isAutoScrollMaxTextureExceeded,
                           ellipsisPosition);
 
   return newLayoutSize;
index a98ef9b..dd50efa 100644 (file)
@@ -1062,6 +1062,7 @@ void TextLabel::SetUpAutoScrolling()
     if(textNaturalSize.width > maxTextureSize)
     {
       mController->SetTextElideEnabled(true);
+      mController->SetAutoScrollMaxTextureExceeded(true);
     }
     GetHeightForWidth(maxTextureSize);
     wrapGap = std::max(maxTextureSize - textNaturalSize.width, 0.0f);
@@ -1089,6 +1090,7 @@ void TextLabel::SetUpAutoScrolling()
   Renderer renderer = static_cast<Internal::Visual::Base&>(GetImplementation(mVisual)).GetRenderer();
   mTextScroller->SetParameters(Self(), renderer, textureSet, controlSize, verifiedSize, wrapGap, direction, mController->GetHorizontalAlignment(), mController->GetVerticalAlignment());
   mController->SetTextElideEnabled(actualellipsis);
+  mController->SetAutoScrollMaxTextureExceeded(false);
 }
 
 void TextLabel::ScrollingFinished()
index 7610b67..a1603e6 100644 (file)
@@ -1215,16 +1215,22 @@ struct Engine::Impl
                     Length&                           numberOfLines,
                     float                             penY,
                     bool&                             isAutoScrollEnabled,
+                    bool                              isAutoScrollMaxTextureExceeded,
                     DevelText::EllipsisPosition::Type ellipsisPosition,
                     bool                              enforceEllipsisInSingleLine)
   {
-    const bool ellipsis    = enforceEllipsisInSingleLine || (isAutoScrollEnabled ? (penY - layout.descender > layoutParameters.boundingBox.height) : ((penY - layout.descender > layoutParameters.boundingBox.height) || ((mLayout == SINGLE_LINE_BOX) && (layout.length > layoutParameters.boundingBox.width))));
+    const bool ellipsis    = enforceEllipsisInSingleLine || (isAutoScrollEnabled ? isAutoScrollMaxTextureExceeded : ((penY - layout.descender > layoutParameters.boundingBox.height) || ((mLayout == SINGLE_LINE_BOX) && (layout.length > layoutParameters.boundingBox.width))));
     const bool isMultiline = !enforceEllipsisInSingleLine && (mLayout == MULTI_LINE_BOX);
     if(ellipsis && (ellipsisPosition == DevelText::EllipsisPosition::END || !isMultiline))
     {
-      isAutoScrollEnabled = false;
-      // Do not layout more lines if ellipsis is enabled.
+      if(penY - layout.descender > layoutParameters.boundingBox.height)
+      {
+        // Even if auto scroll is enabled and text is bigger than max texture size,
+        // if the the height is small, auto scroll should not work.
+        isAutoScrollEnabled = false;
+      }
 
+      // Do not layout more lines if ellipsis is enabled.
       // The last line needs to be completely filled with characters.
       // Part of a word may be used.
 
@@ -1500,6 +1506,7 @@ struct Engine::Impl
                   Size&                             layoutSize,
                   bool                              elideTextEnabled,
                   bool&                             isAutoScrollEnabled,
+                  bool                              isAutoScrollMaxTextureExceeded,
                   DevelText::EllipsisPosition::Type ellipsisPosition)
   {
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->LayoutText\n");
@@ -1726,6 +1733,7 @@ struct Engine::Impl
                                 numberOfLines,
                                 penY,
                                 isAutoScrollEnabled,
+                                isAutoScrollMaxTextureExceeded,
                                 ellipsisPosition,
                                 false);
       }
@@ -1744,6 +1752,7 @@ struct Engine::Impl
                                   numberOfLines,
                                   penY,
                                   isAutoScrollEnabled,
+                                  isAutoScrollMaxTextureExceeded,
                                   ellipsisPosition,
                                   true);
         }
@@ -2144,12 +2153,14 @@ bool Engine::LayoutText(Parameters&                       layoutParameters,
                         Size&                             layoutSize,
                         bool                              elideTextEnabled,
                         bool&                             isAutoScrollEnabled,
+                        bool                              isAutoScrollMaxTextureExceeded,
                         DevelText::EllipsisPosition::Type ellipsisPosition)
 {
   return mImpl->LayoutText(layoutParameters,
                            layoutSize,
                            elideTextEnabled,
                            isAutoScrollEnabled,
+                           isAutoScrollMaxTextureExceeded,
                            ellipsisPosition);
 }
 
index e11c549..1e664b8 100644 (file)
@@ -107,6 +107,7 @@ public:
    * @param[out] layoutSize The size of the text after it has been laid-out.
    * @param[in] elideTextEnabled Whether the text elide is enabled.
    * @param[in,out] isAutoScrollEnabled If the isAutoScrollEnabled is true and the height of the text exceeds the boundaries of the control the text is elided and the isAutoScrollEnabled is set to false to disable the autoscroll
+   * @param[in] isAutoScrollMaxTextureExceeded If isAutoScrollMaxTextureExceeded is true, enable ellipsis during auto scroll.
    * @param[in] ellipsisPosition The location of the text ellipsis
    *
    * @return \e true if the text has been re-laid-out. \e false means the given width is too small to layout even a single character.
@@ -115,6 +116,7 @@ public:
                   Size&                             layoutSize,
                   bool                              elideTextEnabled,
                   bool&                             isAutoScrollEnabled,
+                  bool                              isAutoScrollMaxTextureExceeded,
                   DevelText::EllipsisPosition::Type ellipsisPosition);
 
   /**
index 9b7772e..1e3fade 100644 (file)
@@ -345,6 +345,7 @@ struct Controller::Impl
     mMarkupProcessorEnabled(false),
     mClipboardHideEnabled(true),
     mIsAutoScrollEnabled(false),
+    mIsAutoScrollMaxTextureExceeded(false),
     mUpdateTextDirection(true),
     mIsTextDirectionRTL(false),
     mUnderlineSetByString(false),
@@ -892,12 +893,13 @@ public:
   std::unique_ptr<InputFilter> mInputFilter;                ///< Avoid allocating this when the user does not specify input filter mode.
   Vector2                      mTextFitContentSize;         ///< Size of Text fit content
 
-  bool               mRecalculateNaturalSize : 1; ///< Whether the natural size needs to be recalculated.
-  bool               mMarkupProcessorEnabled : 1; ///< Whether the mark-up procesor is enabled.
-  bool               mClipboardHideEnabled : 1;   ///< Whether the ClipboardHide function work or not
-  bool               mIsAutoScrollEnabled : 1;    ///< Whether auto text scrolling is enabled.
-  bool               mUpdateTextDirection : 1;    ///< Whether the text direction needs to be updated.
-  CharacterDirection mIsTextDirectionRTL : 1;     ///< Whether the text direction is right to left or not
+  bool               mRecalculateNaturalSize : 1;         ///< Whether the natural size needs to be recalculated.
+  bool               mMarkupProcessorEnabled : 1;         ///< Whether the mark-up procesor is enabled.
+  bool               mClipboardHideEnabled : 1;           ///< Whether the ClipboardHide function work or not
+  bool               mIsAutoScrollEnabled : 1;            ///< Whether auto text scrolling is enabled.
+  bool               mIsAutoScrollMaxTextureExceeded : 1; ///< Whether auto text scrolling is exceed max texture size.
+  bool               mUpdateTextDirection : 1;            ///< Whether the text direction needs to be updated.
+  CharacterDirection mIsTextDirectionRTL : 1;             ///< Whether the text direction is right to left or not
 
   bool                  mUnderlineSetByString : 1;     ///< Set when underline is set by string (legacy) instead of map
   bool                  mShadowSetByString : 1;        ///< Set when shadow is set by string (legacy) instead of map
index 8e82db5..742089c 100644 (file)
@@ -48,7 +48,7 @@ namespace Toolkit
 {
 namespace Text
 {
-Size Controller::Relayouter::CalculateLayoutSizeOnRequiredControllerSize(Controller& controller, const Size& requestedControllerSize, const OperationsMask& requestedOperationsMask, bool restoreLinesAndGlyphPositions)
+Size Controller::Relayouter::CalculateLayoutSizeOnRequiredControllerSize(Controller& controller, const Size& requestedControllerSize, const OperationsMask& requestedOperationsMask)
 {
   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->CalculateLayoutSizeOnRequiredControllerSize\n");
   Size calculatedLayoutSize;
@@ -57,17 +57,6 @@ Size Controller::Relayouter::CalculateLayoutSizeOnRequiredControllerSize(Control
   ModelPtr&         model       = impl.mModel;
   VisualModelPtr&   visualModel = model->mVisualModel;
 
-  // Store the pending operations mask so that it can be restored later on with no modifications made on it
-  // while getting the natural size were reflected on the original mask.
-  OperationsMask operationsPendingBackUp = static_cast<OperationsMask>(impl.mOperationsPending);
-
-  // This is a hotfix for side effect on Scrolling, LineWrap and Invalid position of cursor in TextEditor after calling CalculateLayoutSizeOnRequiredControllerSize.
-  // The number of lines and glyph-positions inside visualModel have been changed by calling DoRelayout with requestedControllerSize.
-  // Store the mLines and mGlyphPositions from visualModel so that they can be restored later on with no modifications made on them.
-  //TODO: Refactor "DoRelayout" and extract common code of size calculation without modifying attributes of mVisualModel, and then blah, blah, etc.
-  Vector<LineRun> linesBackup          = visualModel->mLines;
-  Vector<Vector2> glyphPositionsBackup = visualModel->mGlyphPositions;
-
   // Operations that can be done only once until the text changes.
   const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
                                                                         GET_SCRIPTS |
@@ -77,6 +66,8 @@ Size Controller::Relayouter::CalculateLayoutSizeOnRequiredControllerSize(Control
                                                                         SHAPE_TEXT |
                                                                         GET_GLYPH_METRICS);
 
+  const OperationsMask sizeOperations = static_cast<OperationsMask>(LAYOUT | ALIGN | REORDER);
+
   // Set the update info to relayout the whole text.
   TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
   if((0 == textUpdateInfo.mNumberOfCharactersToAdd) &&
@@ -88,40 +79,79 @@ Size Controller::Relayouter::CalculateLayoutSizeOnRequiredControllerSize(Control
   textUpdateInfo.mParagraphCharacterIndex     = 0u;
   textUpdateInfo.mRequestedNumberOfCharacters = model->mLogicalModel->mText.Count();
 
-  // Make sure the model is up-to-date before layouting
-  impl.UpdateModel(onlyOnceOperations);
-
   // Get a reference to the pending operations member
   OperationsMask& operationsPending = impl.mOperationsPending;
 
-  // Layout the text for the new width.
-  operationsPending = static_cast<OperationsMask>(operationsPending | requestedOperationsMask);
-
   // Store the actual control's size to restore later.
   const Size actualControlSize = visualModel->mControlSize;
 
-  DoRelayout(controller,
-             requestedControllerSize,
-             static_cast<OperationsMask>(onlyOnceOperations |
-                                         requestedOperationsMask),
-             calculatedLayoutSize);
+  // Whether the text control is editable
+  const bool isEditable = NULL != impl.mEventData;
 
-  // Clear the update info. This info will be set the next time the text is updated.
-  textUpdateInfo.Clear();
-  textUpdateInfo.mClearAll = true;
+  if(!isEditable)
+  {
+    impl.UpdateModel(onlyOnceOperations);
 
-  // Restore the actual control's size.
-  visualModel->mControlSize = actualControlSize;
-  // Restore the previously backed-up pending operations' mask without the only once operations.
-  impl.mOperationsPending = static_cast<OperationsMask>(operationsPendingBackUp & ~onlyOnceOperations);
+    if(impl.mIsAutoScrollEnabled)
+    {
+      // Layout the text for the new width.
+      operationsPending = static_cast<OperationsMask>(operationsPending | requestedOperationsMask);
+    }
+
+    DoRelayout(controller,
+               requestedControllerSize,
+               static_cast<OperationsMask>(onlyOnceOperations | requestedOperationsMask),
+               calculatedLayoutSize);
+
+    textUpdateInfo.Clear();
+    textUpdateInfo.mClearAll = true;
 
-  // Restore the previously backed-up mLines and mGlyphPositions from visualModel.
-  if(restoreLinesAndGlyphPositions)
+    // Do not do again the only once operations.
+    operationsPending = static_cast<OperationsMask>(operationsPending & ~onlyOnceOperations);
+  }
+  else
   {
-    visualModel->mLines          = linesBackup;
-    visualModel->mGlyphPositions = glyphPositionsBackup;
+    // 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
+    operationsPending = static_cast<OperationsMask>(operationsPending | requestedOperationsMask | onlyOnceOperations);
+
+    // Make sure the model is up-to-date before layouting
+    impl.UpdateModel(static_cast<OperationsMask>(operationsPending & ~UPDATE_LAYOUT_SIZE));
+
+    DoRelayout(controller,
+               requestedControllerSize,
+               static_cast<OperationsMask>(operationsPending & ~UPDATE_LAYOUT_SIZE),
+               calculatedLayoutSize);
+
+    // Clear the update info. This info will be set the next time the text is updated.
+    textUpdateInfo.Clear();
+
+    //TODO: Refactor "DoRelayout" and extract common code of size calculation without modifying attributes of mVisualModel,
+    //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;
+
+    // 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);
+
+  // Restore the actual control's size.
+  visualModel->mControlSize = actualControlSize;
+
   return calculatedLayoutSize;
 }
 
@@ -145,7 +175,7 @@ Vector3 Controller::Relayouter::GetNaturalSize(Controller& controller)
     OperationsMask requestedOperationsMask  = static_cast<OperationsMask>(LAYOUT | REORDER);
     Size           sizeMaxWidthAndMaxHeight = Size(MAX_FLOAT, MAX_FLOAT);
 
-    naturalSize = CalculateLayoutSizeOnRequiredControllerSize(controller, sizeMaxWidthAndMaxHeight, requestedOperationsMask, true);
+    naturalSize = CalculateLayoutSizeOnRequiredControllerSize(controller, sizeMaxWidthAndMaxHeight, requestedOperationsMask);
 
     // Stores the natural size to avoid recalculate it again
     // unless the text/style changes.
@@ -294,15 +324,7 @@ float Controller::Relayouter::GetHeightForWidth(Controller& controller, float wi
     OperationsMask requestedOperationsMask        = static_cast<OperationsMask>(LAYOUT);
     Size           sizeRequestedWidthAndMaxHeight = Size(width, MAX_FLOAT);
 
-    // Skip restore, because if GetHeightForWidth called before rendering and layouting then visualModel->mControlSize will be zero which will make LineCount zero.
-    // The implementation of Get LineCount property depends on calling GetHeightForWidth then read mLines.Count() from visualModel direct.
-    // If the LineCount property is requested before rendering and layouting then the value will be zero, which is incorrect.
-    // So we will not restore the previously backed-up mLines and mGlyphPositions from visualModel in such case.
-    // Another case to skip restore is when the requested width equals the Control's width which means the caller need to update the old values.
-    // For example, when the text is changed.
-    bool restoreLinesAndGlyphPositions = (visualModel->mControlSize.width > 0 && visualModel->mControlSize.height > 0) && (visualModel->mControlSize.width != width);
-
-    layoutSize = CalculateLayoutSizeOnRequiredControllerSize(controller, sizeRequestedWidthAndMaxHeight, requestedOperationsMask, restoreLinesAndGlyphPositions);
+    layoutSize = CalculateLayoutSizeOnRequiredControllerSize(controller, sizeRequestedWidthAndMaxHeight, requestedOperationsMask);
 
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height);
   }
@@ -593,11 +615,13 @@ bool Controller::Relayouter::DoRelayout(Controller& controller, const Size& size
 
     // Update the visual model.
     bool isAutoScrollEnabled = impl.mIsAutoScrollEnabled;
+    bool isAutoScrollMaxTextureExceeded = impl.mIsAutoScrollMaxTextureExceeded;
     Size newLayoutSize;
-    viewUpdated               = impl.mLayoutEngine.LayoutText(layoutParameters,
+    viewUpdated = impl.mLayoutEngine.LayoutText(layoutParameters,
                                                 newLayoutSize,
                                                 elideTextEnabled,
                                                 isAutoScrollEnabled,
+                                                isAutoScrollMaxTextureExceeded,
                                                 ellipsisPosition);
     impl.mIsAutoScrollEnabled = isAutoScrollEnabled;
 
index 1b586b2..9a67ab8 100644 (file)
@@ -109,11 +109,10 @@ struct Controller::Relayouter
   * @param[in] controller The controller to calcualte size on it.
   * @param[in] requestedControllerSize The requested size of controller to calcualte layout size on it.
   * @param[in] requestedOperationsMask The requested operations-mask to calcualte layout size according to it.
-  * @param[in] restoreLinesAndGlyphPositions whether to restore lines and glyph-positions to status before requesting calculation on size.
   *
   * @return The calculated layout-size.
   */
-  static Size CalculateLayoutSizeOnRequiredControllerSize(Controller& controller, const Size& requestedControllerSize, const OperationsMask& requestedOperationsMask, bool restoreLinesAndGlyphPositions);
+  static Size CalculateLayoutSizeOnRequiredControllerSize(Controller& controller, const Size& requestedControllerSize, const OperationsMask& requestedOperationsMask);
 
 };
 
index 4ec306b..3001056 100644 (file)
@@ -173,6 +173,11 @@ void Controller::SetAutoScrollEnabled(bool enable)
   mImpl->SetAutoScrollEnabled(enable);
 }
 
+void Controller::SetAutoScrollMaxTextureExceeded(bool exceed)
+{
+  mImpl->mIsAutoScrollMaxTextureExceeded = exceed;
+}
+
 bool Controller::IsAutoScrollEnabled() const
 {
   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", mImpl->mIsAutoScrollEnabled ? "true" : "false");
index a5bc8b4..d29f929 100644 (file)
@@ -256,6 +256,15 @@ public: // Configure the text controller.
   void SetAutoScrollEnabled(bool enable);
 
   /**
+   * @brief Whether the auto scrolling texture exceed max texture.
+   *
+   * By default is false.
+   *
+   * @param[in] exceed Whether the auto scrolling texture exceed max texture.
+   */
+  void SetAutoScrollMaxTextureExceeded(bool exceed);
+
+  /**
    * @brief Retrieves whether auto text scrolling is enabled.
    *
    * By default is disabled.