(TextController) Reformatted to reduce LOC
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-selection-handle-controller.cpp
index 664b59e..cf63deb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,7 +29,6 @@ using namespace Dali;
 
 namespace
 {
-
 /**
  * @brief Struct used to calculate the selection box.
  */
@@ -45,196 +44,191 @@ struct SelectionBoxInfo
 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
 #endif
 
-const float MAX_FLOAT = std::numeric_limits<float>::max();
-const float MIN_FLOAT = std::numeric_limits<float>::min();
-const Dali::Toolkit::Text::CharacterDirection LTR = false; ///< Left To Right direction
+const float                                   MAX_FLOAT = std::numeric_limits<float>::max();
+const float                                   MIN_FLOAT = std::numeric_limits<float>::min();
+const Dali::Toolkit::Text::CharacterDirection LTR       = false; ///< Left To Right direction
 
 } // namespace
 
 namespace Dali
 {
-
 namespace Toolkit
 {
-
 namespace Text
 {
-
 void SelectionHandleController::Reposition(Controller::Impl& impl)
 {
   EventData*& eventData = impl.mEventData;
 
   CharacterIndex selectionStart = eventData->mLeftSelectionPosition;
-  CharacterIndex selectionEnd = eventData->mRightSelectionPosition;
+  CharacterIndex selectionEnd   = eventData->mRightSelectionPosition;
 
   DecoratorPtr& decorator = eventData->mDecorator;
 
-  if( selectionStart == selectionEnd )
+  if(selectionStart == selectionEnd)
   {
     // Nothing to select if handles are in the same place.
     // So, deactive Highlight box.
-    decorator->SetHighlightActive( false );
+    decorator->SetHighlightActive(false);
     return;
   }
 
   decorator->ClearHighlights();
 
-  ModelPtr& model = impl.mModel;
-  VisualModelPtr& visualModel = model->mVisualModel;
+  ModelPtr&        model        = impl.mModel;
+  VisualModelPtr&  visualModel  = model->mVisualModel;
   LogicalModelPtr& logicalModel = model->mLogicalModel;
 
-  const GlyphIndex* const charactersToGlyphBuffer = visualModel->mCharactersToGlyph.Begin();
-  const Length* const glyphsPerCharacterBuffer = visualModel->mGlyphsPerCharacter.Begin();
-  const GlyphInfo* const glyphsBuffer = visualModel->mGlyphs.Begin();
-  const Vector2* const positionsBuffer = visualModel->mGlyphPositions.Begin();
-  const Length* const charactersPerGlyphBuffer = visualModel->mCharactersPerGlyph.Begin();
-  const CharacterIndex* const glyphToCharacterBuffer = visualModel->mGlyphsToCharacters.Begin();
-  const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != logicalModel->mCharacterDirections.Count() ) ? logicalModel->mCharacterDirections.Begin() : NULL;
+  const GlyphIndex* const         charactersToGlyphBuffer        = visualModel->mCharactersToGlyph.Begin();
+  const Length* const             glyphsPerCharacterBuffer       = visualModel->mGlyphsPerCharacter.Begin();
+  const GlyphInfo* const          glyphsBuffer                   = visualModel->mGlyphs.Begin();
+  const Vector2* const            positionsBuffer                = visualModel->mGlyphPositions.Begin();
+  const Length* const             charactersPerGlyphBuffer       = visualModel->mCharactersPerGlyph.Begin();
+  const CharacterIndex* const     glyphToCharacterBuffer         = visualModel->mGlyphsToCharacters.Begin();
+  const CharacterDirection* const modelCharacterDirectionsBuffer = (0u != logicalModel->mCharacterDirections.Count()) ? logicalModel->mCharacterDirections.Begin() : NULL;
 
-  const bool isLastCharacter = selectionEnd >= logicalModel->mText.Count();
-  const CharacterDirection startDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + selectionStart ) );
-  const CharacterDirection endDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + ( selectionEnd - ( isLastCharacter ? 1u : 0u ) ) ) );
+  const bool               isLastCharacter = selectionEnd >= logicalModel->mText.Count();
+  const CharacterDirection startDirection  = ((NULL == modelCharacterDirectionsBuffer) ? false : *(modelCharacterDirectionsBuffer + selectionStart));
+  const CharacterDirection endDirection    = ((NULL == modelCharacterDirectionsBuffer) ? false : *(modelCharacterDirectionsBuffer + (selectionEnd - (isLastCharacter ? 1u : 0u))));
 
   // Swap the indices if the start is greater than the end.
   const bool indicesSwapped = selectionStart > selectionEnd;
 
   // Tell the decorator to flip the selection handles if needed.
-  decorator->SetSelectionHandleFlipState( indicesSwapped, startDirection, endDirection );
+  decorator->SetSelectionHandleFlipState(indicesSwapped, startDirection, endDirection);
 
-  if( indicesSwapped )
+  if(indicesSwapped)
   {
-    std::swap( selectionStart, selectionEnd );
+    std::swap(selectionStart, selectionEnd);
   }
 
   // Get the indices to the first and last selected glyphs.
   const CharacterIndex selectionEndMinusOne = selectionEnd - 1u;
-  const GlyphIndex glyphStart = *( charactersToGlyphBuffer + selectionStart );
-  const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + selectionEndMinusOne );
-  const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + selectionEndMinusOne ) + ( ( numberOfGlyphs > 0 ) ? numberOfGlyphs - 1u : 0u );
+  const GlyphIndex     glyphStart           = *(charactersToGlyphBuffer + selectionStart);
+  const Length         numberOfGlyphs       = *(glyphsPerCharacterBuffer + selectionEndMinusOne);
+  const GlyphIndex     glyphEnd             = *(charactersToGlyphBuffer + selectionEndMinusOne) + ((numberOfGlyphs > 0) ? numberOfGlyphs - 1u : 0u);
 
   // Get the lines where the glyphs are laid-out.
   const LineRun* lineRun = visualModel->mLines.Begin();
 
-  LineIndex lineIndex = 0u;
-  Length numberOfLines = 0u;
-  visualModel->GetNumberOfLines( glyphStart,
-                                 1u + glyphEnd - glyphStart,
-                                 lineIndex,
-                                 numberOfLines );
+  LineIndex lineIndex     = 0u;
+  Length    numberOfLines = 0u;
+  visualModel->GetNumberOfLines(glyphStart,
+                                1u + glyphEnd - glyphStart,
+                                lineIndex,
+                                numberOfLines);
   const LineIndex firstLineIndex = lineIndex;
 
   // Create the structure to store some selection box info.
   Vector<SelectionBoxInfo> selectionBoxLinesInfo;
-  selectionBoxLinesInfo.Resize( numberOfLines );
+  selectionBoxLinesInfo.Resize(numberOfLines);
 
   SelectionBoxInfo* selectionBoxInfo = selectionBoxLinesInfo.Begin();
-  selectionBoxInfo->minX = MAX_FLOAT;
-  selectionBoxInfo->maxX = MIN_FLOAT;
+  selectionBoxInfo->minX             = MAX_FLOAT;
+  selectionBoxInfo->maxX             = MIN_FLOAT;
 
   // Keep the min and max 'x' position to calculate the size and position of the highlighed text.
-  float minHighlightX = std::numeric_limits<float>::max();
-  float maxHighlightX = std::numeric_limits<float>::min();
-  Size highLightSize;
+  float   minHighlightX = std::numeric_limits<float>::max();
+  float   maxHighlightX = std::numeric_limits<float>::min();
+  Size    highLightSize;
   Vector2 highLightPosition; // The highlight position in decorator's coords.
 
   // Retrieve the first line and get the line's vertical offset, the line's height and the index to the last glyph.
 
   // The line's vertical offset of all the lines before the line where the first glyph is laid-out.
-  selectionBoxInfo->lineOffset = CalculateLineOffset( visualModel->mLines,
-                                                      firstLineIndex );
+  selectionBoxInfo->lineOffset = CalculateLineOffset(visualModel->mLines,
+                                                     firstLineIndex);
 
   // Transform to decorator's (control) coords.
   selectionBoxInfo->lineOffset += model->mScrollPosition.y;
 
   lineRun += firstLineIndex;
 
-  // The line height is the addition of the line ascender and the line descender.
-  // However, the line descender has a negative value, hence the subtraction.
-  selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
+  selectionBoxInfo->lineHeight = GetLineHeight(*lineRun);
 
   GlyphIndex lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
 
   // Check if the first glyph is a ligature that must be broken like Latin ff, fi, or Arabic ﻻ, etc which needs special code.
-  const Length numberOfCharactersStart = *( charactersPerGlyphBuffer + glyphStart );
-  bool splitStartGlyph = ( numberOfCharactersStart > 1u ) && HasLigatureMustBreak( logicalModel->GetScript( selectionStart ) );
+  const Length numberOfCharactersStart = *(charactersPerGlyphBuffer + glyphStart);
+  bool         splitStartGlyph         = (numberOfCharactersStart > 1u) && HasLigatureMustBreak(logicalModel->GetScript(selectionStart));
 
   // Check if the last glyph is a ligature that must be broken like Latin ff, fi, or Arabic ﻻ, etc which needs special code.
-  const Length numberOfCharactersEnd = *( charactersPerGlyphBuffer + glyphEnd );
-  bool splitEndGlyph = ( glyphStart != glyphEnd ) && ( numberOfCharactersEnd > 1u ) && HasLigatureMustBreak( logicalModel->GetScript( selectionEndMinusOne ) );
+  const Length numberOfCharactersEnd = *(charactersPerGlyphBuffer + glyphEnd);
+  bool         splitEndGlyph         = (glyphStart != glyphEnd) && (numberOfCharactersEnd > 1u) && HasLigatureMustBreak(logicalModel->GetScript(selectionEndMinusOne));
 
   // The number of quads of the selection box.
-  const unsigned int numberOfQuads = 1u + ( glyphEnd - glyphStart ) + ( ( numberOfLines > 1u ) ? 2u * numberOfLines : 0u );
-  decorator->ResizeHighlightQuads( numberOfQuads );
+  const unsigned int numberOfQuads = 1u + (glyphEnd - glyphStart) + ((numberOfLines > 1u) ? 2u * numberOfLines : 0u);
+  decorator->ResizeHighlightQuads(numberOfQuads);
 
   // Count the actual number of quads.
   unsigned int actualNumberOfQuads = 0u;
-  Vector4 quad;
+  Vector4      quad;
 
   // Traverse the glyphs.
-  for( GlyphIndex index = glyphStart; index <= glyphEnd; ++index )
+  for(GlyphIndex index = glyphStart; index <= glyphEnd; ++index)
   {
-    const GlyphInfo& glyph = *( glyphsBuffer + index );
-    const Vector2& position = *( positionsBuffer + index );
+    const GlyphInfo& glyph    = *(glyphsBuffer + index);
+    const Vector2&   position = *(positionsBuffer + index);
 
-    if( splitStartGlyph )
+    if(splitStartGlyph)
     {
       // If the first glyph is a ligature that must be broken it may be needed to add only part of the glyph to the highlight box.
 
-      const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersStart );
-      const CharacterIndex interGlyphIndex = selectionStart - *( glyphToCharacterBuffer + glyphStart );
+      const float          glyphAdvance    = glyph.advance / static_cast<float>(numberOfCharactersStart);
+      const CharacterIndex interGlyphIndex = selectionStart - *(glyphToCharacterBuffer + glyphStart);
       // Get the direction of the character.
       CharacterDirection isCurrentRightToLeft = false;
-      if( nullptr != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
+      if(nullptr != modelCharacterDirectionsBuffer) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
       {
-        isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionStart );
+        isCurrentRightToLeft = *(modelCharacterDirectionsBuffer + selectionStart);
       }
 
       // The end point could be in the middle of the ligature.
       // Calculate the number of characters selected.
-      const Length numberOfCharacters = ( glyphStart == glyphEnd ) ? ( selectionEnd - selectionStart ) : ( numberOfCharactersStart - interGlyphIndex );
+      const Length numberOfCharacters = (glyphStart == glyphEnd) ? (selectionEnd - selectionStart) : (numberOfCharactersStart - interGlyphIndex);
 
-      quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + model->mScrollPosition.x + glyphAdvance * static_cast<float>( isCurrentRightToLeft ? ( numberOfCharactersStart - interGlyphIndex - numberOfCharacters ) : interGlyphIndex );
+      quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + model->mScrollPosition.x + glyphAdvance * static_cast<float>(isCurrentRightToLeft ? (numberOfCharactersStart - interGlyphIndex - numberOfCharacters) : interGlyphIndex);
       quad.y = selectionBoxInfo->lineOffset;
-      quad.z = quad.x + static_cast<float>( numberOfCharacters ) * glyphAdvance;
+      quad.z = quad.x + static_cast<float>(numberOfCharacters) * glyphAdvance;
       quad.w = selectionBoxInfo->lineOffset + selectionBoxInfo->lineHeight;
 
       // Store the min and max 'x' for each line.
-      selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
-      selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
+      selectionBoxInfo->minX = std::min(selectionBoxInfo->minX, quad.x);
+      selectionBoxInfo->maxX = std::max(selectionBoxInfo->maxX, quad.z);
 
-      decorator->AddHighlight( actualNumberOfQuads, quad );
+      decorator->AddHighlight(actualNumberOfQuads, quad);
       ++actualNumberOfQuads;
 
       splitStartGlyph = false;
       continue;
     }
 
-    if( splitEndGlyph && ( index == glyphEnd ) )
+    if(splitEndGlyph && (index == glyphEnd))
     {
       // Equally, if the last glyph is a ligature that must be broken it may be needed to add only part of the glyph to the highlight box.
 
-      const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersEnd );
-      const CharacterIndex interGlyphIndex = selectionEnd - *( glyphToCharacterBuffer + glyphEnd );
+      const float          glyphAdvance    = glyph.advance / static_cast<float>(numberOfCharactersEnd);
+      const CharacterIndex interGlyphIndex = selectionEnd - *(glyphToCharacterBuffer + glyphEnd);
       // Get the direction of the character.
       CharacterDirection isCurrentRightToLeft = false;
-      if( nullptr != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
+      if(nullptr != modelCharacterDirectionsBuffer) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
       {
-        isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionEnd );
+        isCurrentRightToLeft = *(modelCharacterDirectionsBuffer + selectionEnd);
       }
 
       const Length numberOfCharacters = numberOfCharactersEnd - interGlyphIndex;
 
-      quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + model->mScrollPosition.x + ( isCurrentRightToLeft ? ( glyphAdvance * static_cast<float>( numberOfCharacters ) ) : 0.f );
+      quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + model->mScrollPosition.x + (isCurrentRightToLeft ? (glyphAdvance * static_cast<float>(numberOfCharacters)) : 0.f);
       quad.y = selectionBoxInfo->lineOffset;
-      quad.z = quad.x + static_cast<float>( interGlyphIndex ) * glyphAdvance;
+      quad.z = quad.x + static_cast<float>(interGlyphIndex) * glyphAdvance;
       quad.w = quad.y + selectionBoxInfo->lineHeight;
 
       // Store the min and max 'x' for each line.
-      selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
-      selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
+      selectionBoxInfo->minX = std::min(selectionBoxInfo->minX, quad.x);
+      selectionBoxInfo->maxX = std::max(selectionBoxInfo->maxX, quad.z);
 
-      decorator->AddHighlight( actualNumberOfQuads,
-                                            quad );
+      decorator->AddHighlight(actualNumberOfQuads,
+                              quad);
       ++actualNumberOfQuads;
 
       splitEndGlyph = false;
@@ -247,18 +241,18 @@ void SelectionHandleController::Reposition(Controller::Impl& impl)
     quad.w = quad.y + selectionBoxInfo->lineHeight;
 
     // Store the min and max 'x' for each line.
-    selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
-    selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
+    selectionBoxInfo->minX = std::min(selectionBoxInfo->minX, quad.x);
+    selectionBoxInfo->maxX = std::max(selectionBoxInfo->maxX, quad.z);
 
-    decorator->AddHighlight( actualNumberOfQuads,
-                                          quad );
+    decorator->AddHighlight(actualNumberOfQuads,
+                            quad);
     ++actualNumberOfQuads;
 
     // Whether to retrieve the next line.
-    if( index == lastGlyphOfLine )
+    if(index == lastGlyphOfLine)
     {
       ++lineIndex;
-      if( lineIndex < firstLineIndex + numberOfLines )
+      if(lineIndex < firstLineIndex + numberOfLines)
       {
         // Retrieve the next line.
         ++lineRun;
@@ -279,40 +273,38 @@ void SelectionHandleController::Reposition(Controller::Impl& impl)
         // Update the line's vertical offset.
         selectionBoxInfo->lineOffset = currentLineOffset + currentLineHeight;
 
-        // The line height is the addition of the line ascender and the line descender.
-        // However, the line descender has a negative value, hence the subtraction.
-        selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
+        selectionBoxInfo->lineHeight = GetLineHeight(*lineRun);
       }
     }
   }
 
   // Traverses all the lines and updates the min and max 'x' positions and the total height.
   // The final width is calculated after 'boxifying' the selection.
-  for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin(),
-         endIt = selectionBoxLinesInfo.End();
-       it != endIt;
-       ++it )
+  for(Vector<SelectionBoxInfo>::ConstIterator it    = selectionBoxLinesInfo.Begin(),
+                                              endIt = selectionBoxLinesInfo.End();
+      it != endIt;
+      ++it)
   {
     const SelectionBoxInfo& info = *it;
 
     // Update the size of the highlighted text.
     highLightSize.height += info.lineHeight;
-    minHighlightX = std::min( minHighlightX, info.minX );
-    maxHighlightX = std::max( maxHighlightX, info.maxX );
+    minHighlightX = std::min(minHighlightX, info.minX);
+    maxHighlightX = std::max(maxHighlightX, info.maxX);
   }
 
   // Add extra geometry to 'boxify' the selection.
 
-  if( 1u < numberOfLines )
+  if(1u < numberOfLines)
   {
     // Boxify the first line.
-    lineRun = visualModel->mLines.Begin() + firstLineIndex;
-    const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
+    lineRun                                           = visualModel->mLines.Begin() + firstLineIndex;
+    const SelectionBoxInfo& firstSelectionBoxLineInfo = *(selectionBoxLinesInfo.Begin());
 
-    bool boxifyBegin = ( LTR != lineRun->direction ) && ( LTR != startDirection );
-    bool boxifyEnd = ( LTR == lineRun->direction ) && ( LTR == startDirection );
+    bool boxifyBegin = (LTR != lineRun->direction) && (LTR != startDirection);
+    bool boxifyEnd   = (LTR == lineRun->direction) && (LTR == startDirection);
 
-    if( boxifyBegin )
+    if(boxifyBegin)
     {
       quad.x = 0.f;
       quad.y = firstSelectionBoxLineInfo.lineOffset;
@@ -320,15 +312,15 @@ void SelectionHandleController::Reposition(Controller::Impl& impl)
       quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
 
       // Boxify at the beginning of the line.
-      decorator->AddHighlight( actualNumberOfQuads,
-                                            quad );
+      decorator->AddHighlight(actualNumberOfQuads,
+                              quad);
       ++actualNumberOfQuads;
 
       // Update the size of the highlighted text.
       minHighlightX = 0.f;
     }
 
-    if( boxifyEnd )
+    if(boxifyEnd)
     {
       quad.x = firstSelectionBoxLineInfo.maxX;
       quad.y = firstSelectionBoxLineInfo.lineOffset;
@@ -336,8 +328,8 @@ void SelectionHandleController::Reposition(Controller::Impl& impl)
       quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
 
       // Boxify at the end of the line.
-      decorator->AddHighlight( actualNumberOfQuads,
-                                            quad );
+      decorator->AddHighlight(actualNumberOfQuads,
+                              quad);
       ++actualNumberOfQuads;
 
       // Update the size of the highlighted text.
@@ -345,12 +337,12 @@ void SelectionHandleController::Reposition(Controller::Impl& impl)
     }
 
     // Boxify the central lines.
-    if( 2u < numberOfLines )
+    if(2u < numberOfLines)
     {
-      for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin() + 1u,
-             endIt = selectionBoxLinesInfo.End() - 1u;
-           it != endIt;
-           ++it )
+      for(Vector<SelectionBoxInfo>::ConstIterator it    = selectionBoxLinesInfo.Begin() + 1u,
+                                                  endIt = selectionBoxLinesInfo.End() - 1u;
+          it != endIt;
+          ++it)
       {
         const SelectionBoxInfo& info = *it;
 
@@ -359,8 +351,8 @@ void SelectionHandleController::Reposition(Controller::Impl& impl)
         quad.z = info.minX;
         quad.w = info.lineOffset + info.lineHeight;
 
-        decorator->AddHighlight( actualNumberOfQuads,
-                                              quad );
+        decorator->AddHighlight(actualNumberOfQuads,
+                                quad);
         ++actualNumberOfQuads;
 
         quad.x = info.maxX;
@@ -368,8 +360,8 @@ void SelectionHandleController::Reposition(Controller::Impl& impl)
         quad.z = visualModel->mControlSize.width;
         quad.w = info.lineOffset + info.lineHeight;
 
-        decorator->AddHighlight( actualNumberOfQuads,
-                                              quad );
+        decorator->AddHighlight(actualNumberOfQuads,
+                                quad);
         ++actualNumberOfQuads;
       }
 
@@ -379,13 +371,13 @@ void SelectionHandleController::Reposition(Controller::Impl& impl)
     }
 
     // Boxify the last line.
-    lineRun = visualModel->mLines.Begin() + firstLineIndex + numberOfLines - 1u;
-    const SelectionBoxInfo& lastSelectionBoxLineInfo = *( selectionBoxLinesInfo.End() - 1u );
+    lineRun                                          = visualModel->mLines.Begin() + firstLineIndex + numberOfLines - 1u;
+    const SelectionBoxInfo& lastSelectionBoxLineInfo = *(selectionBoxLinesInfo.End() - 1u);
 
-    boxifyBegin = ( LTR == lineRun->direction ) && ( LTR == endDirection );
-    boxifyEnd = ( LTR != lineRun->direction ) && ( LTR != endDirection );
+    boxifyBegin = (LTR == lineRun->direction) && (LTR == endDirection);
+    boxifyEnd   = (LTR != lineRun->direction) && (LTR != endDirection);
 
-    if( boxifyBegin )
+    if(boxifyBegin)
     {
       quad.x = 0.f;
       quad.y = lastSelectionBoxLineInfo.lineOffset;
@@ -393,15 +385,15 @@ void SelectionHandleController::Reposition(Controller::Impl& impl)
       quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
 
       // Boxify at the beginning of the line.
-      decorator->AddHighlight( actualNumberOfQuads,
-                                            quad );
+      decorator->AddHighlight(actualNumberOfQuads,
+                              quad);
       ++actualNumberOfQuads;
 
       // Update the size of the highlighted text.
       minHighlightX = 0.f;
     }
 
-    if( boxifyEnd )
+    if(boxifyEnd)
     {
       quad.x = lastSelectionBoxLineInfo.maxX;
       quad.y = lastSelectionBoxLineInfo.lineOffset;
@@ -418,19 +410,19 @@ void SelectionHandleController::Reposition(Controller::Impl& impl)
   }
 
   // Set the actual number of quads.
-  decorator->ResizeHighlightQuads( actualNumberOfQuads );
+  decorator->ResizeHighlightQuads(actualNumberOfQuads);
 
   // Sets the highlight's size and position. In decorator's coords.
   // The highlight's height has been calculated above (before 'boxifying' the highlight).
   highLightSize.width = maxHighlightX - minHighlightX;
 
-  highLightPosition.x = minHighlightX;
-  const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
-  highLightPosition.y = firstSelectionBoxLineInfo.lineOffset;
+  highLightPosition.x                               = minHighlightX;
+  const SelectionBoxInfo& firstSelectionBoxLineInfo = *(selectionBoxLinesInfo.Begin());
+  highLightPosition.y                               = firstSelectionBoxLineInfo.lineOffset;
 
-  decorator->SetHighLightBox( highLightPosition, highLightSize, static_cast<float>( model->GetOutlineWidth() ) );
+  decorator->SetHighLightBox(highLightPosition, highLightSize, static_cast<float>(model->GetOutlineWidth()));
 
-  if( !decorator->IsSmoothHandlePanEnabled() )
+  if(!decorator->IsSmoothHandlePanEnabled())
   {
     CursorInfo primaryCursorInfo;
     impl.GetCursorPosition(eventData->mLeftSelectionPosition, primaryCursorInfo);
@@ -440,7 +432,7 @@ void SelectionHandleController::Reposition(Controller::Impl& impl)
     decorator->SetPosition(LEFT_SELECTION_HANDLE,
                            primaryPosition.x,
                            primaryCursorInfo.lineOffset + model->mScrollPosition.y,
-                           primaryCursorInfo.lineHeight );
+                           primaryCursorInfo.lineHeight);
 
     CursorInfo secondaryCursorInfo;
     impl.GetCursorPosition(eventData->mRightSelectionPosition, secondaryCursorInfo);
@@ -450,7 +442,7 @@ void SelectionHandleController::Reposition(Controller::Impl& impl)
     decorator->SetPosition(RIGHT_SELECTION_HANDLE,
                            secondaryPosition.x,
                            secondaryCursorInfo.lineOffset + model->mScrollPosition.y,
-                           secondaryCursorInfo.lineHeight );
+                           secondaryCursorInfo.lineHeight);
   }
 
   // Set the flag to update the decorator.
@@ -472,41 +464,44 @@ void SelectionHandleController::Reposition(Controller::Impl& impl, float visualX
     return;
   }
 
-  ModelPtr& model = impl.mModel;
-  VisualModelPtr& visualModel = model->mVisualModel;
-  const Length numberOfGlyphs = visualModel->mGlyphs.Count();
-  const Length numberOfLines  = visualModel->mLines.Count();
-  if( ( 0 == numberOfGlyphs ) ||
-      ( 0 == numberOfLines ) )
+  ModelPtr&       model          = impl.mModel;
+  VisualModelPtr& visualModel    = model->mVisualModel;
+  const Length    numberOfGlyphs = visualModel->mGlyphs.Count();
+  const Length    numberOfLines  = visualModel->mLines.Count();
+  if((0 == numberOfGlyphs) ||
+     (0 == numberOfLines))
   {
     // Nothing to do if there is no text.
     return;
   }
 
   // Find which word was selected
-  CharacterIndex selectionStart( 0 );
-  CharacterIndex selectionEnd( 0 );
-  CharacterIndex noTextHitIndex( 0 );
-  const bool characterHit = FindSelectionIndices( visualModel,
-                                                  model->mLogicalModel,
-                                                  impl.mMetrics,
-                                                  visualX,
-                                                  visualY,
-                                                  selectionStart,
-                                                  selectionEnd,
-                                                  noTextHitIndex );
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", &impl, selectionStart, selectionEnd );
-
-  if( characterHit || ( Controller::NoTextTap::HIGHLIGHT == action ) )
+  CharacterIndex selectionStart(0);
+  CharacterIndex selectionEnd(0);
+  CharacterIndex noTextHitIndex(0);
+  const bool     characterHit = FindSelectionIndices(visualModel,
+                                                 model->mLogicalModel,
+                                                 impl.mMetrics,
+                                                 visualX,
+                                                 visualY,
+                                                 selectionStart,
+                                                 selectionEnd,
+                                                 noTextHitIndex);
+  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", &impl, selectionStart, selectionEnd);
+
+  if(characterHit || (Controller::NoTextTap::HIGHLIGHT == action))
   {
-    impl.ChangeState( EventData::SELECTING );
+    uint32_t oldStart = eventData->mLeftSelectionPosition;
+    uint32_t oldEnd   = eventData->mRightSelectionPosition;
 
-    eventData->mLeftSelectionPosition = selectionStart;
+    impl.ChangeState(EventData::SELECTING);
+
+    eventData->mLeftSelectionPosition  = selectionStart;
     eventData->mRightSelectionPosition = selectionEnd;
 
-    eventData->mUpdateLeftSelectionPosition = true;
+    eventData->mUpdateLeftSelectionPosition  = true;
     eventData->mUpdateRightSelectionPosition = true;
-    eventData->mUpdateHighlightBox = true;
+    eventData->mUpdateHighlightBox           = true;
 
     // It may happen an InputMethodContext commit event arrives before the selection event
     // if the InputMethodContext is in pre-edit state. The commit event will set the
@@ -514,44 +509,49 @@ void SelectionHandleController::Reposition(Controller::Impl& impl, float visualX
     // to false, the highlight box won't be updated.
     eventData->mUpdateCursorPosition = false;
 
-    eventData->mScrollAfterUpdatePosition = ( eventData->mLeftSelectionPosition != eventData->mRightSelectionPosition );
+    eventData->mScrollAfterUpdatePosition = (eventData->mLeftSelectionPosition != eventData->mRightSelectionPosition);
 
     // Cursor to be positioned at end of selection so if selection interrupted and edit mode restarted the cursor will be at end of selection
-    eventData->mPrimaryCursorPosition = std::max( eventData->mLeftSelectionPosition, eventData->mRightSelectionPosition );
+    eventData->mPrimaryCursorPosition = std::max(eventData->mLeftSelectionPosition, eventData->mRightSelectionPosition);
+
+    if(impl.mSelectableControlInterface != nullptr)
+    {
+      impl.mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, eventData->mLeftSelectionPosition, eventData->mRightSelectionPosition);
+    }
   }
-  else if( Controller::NoTextTap::SHOW_SELECTION_POPUP == action )
+  else if(Controller::NoTextTap::SHOW_SELECTION_POPUP == action)
   {
     // Nothing to select. i.e. a white space, out of bounds
-    impl.ChangeState( EventData::EDITING_WITH_POPUP );
+    impl.ChangeState(EventData::EDITING_WITH_POPUP);
 
     eventData->mPrimaryCursorPosition = noTextHitIndex;
 
-    eventData->mUpdateCursorPosition = true;
-    eventData->mUpdateGrabHandlePosition = true;
+    eventData->mUpdateCursorPosition      = true;
+    eventData->mUpdateGrabHandlePosition  = true;
     eventData->mScrollAfterUpdatePosition = true;
-    eventData->mUpdateInputStyle = true;
+    eventData->mUpdateInputStyle          = true;
   }
-  else if( Controller::NoTextTap::NO_ACTION == action )
+  else if(Controller::NoTextTap::NO_ACTION == action)
   {
     // Nothing to select. i.e. a white space, out of bounds
     eventData->mPrimaryCursorPosition = noTextHitIndex;
 
-    eventData->mUpdateCursorPosition = true;
-    eventData->mUpdateGrabHandlePosition = true;
+    eventData->mUpdateCursorPosition      = true;
+    eventData->mUpdateGrabHandlePosition  = true;
     eventData->mScrollAfterUpdatePosition = true;
-    eventData->mUpdateInputStyle = true;
+    eventData->mUpdateInputStyle          = true;
   }
 }
 
 void SelectionHandleController::Update(Controller::Impl& impl, HandleType handleType, const CursorInfo& cursorInfo)
 {
-  if( ( LEFT_SELECTION_HANDLE != handleType ) &&
-      ( RIGHT_SELECTION_HANDLE != handleType ) )
+  if((LEFT_SELECTION_HANDLE != handleType) &&
+     (RIGHT_SELECTION_HANDLE != handleType))
   {
     return;
   }
 
-  ModelPtr& model = impl.mModel;
+  ModelPtr&     model          = impl.mModel;
   const Vector2 cursorPosition = cursorInfo.primaryPosition + model->mScrollPosition;
 
   // Sets the handle's position.
@@ -559,12 +559,12 @@ void SelectionHandleController::Update(Controller::Impl& impl, HandleType handle
   eventData->mDecorator->SetPosition(handleType,
                                      cursorPosition.x,
                                      cursorInfo.lineOffset + model->mScrollPosition.y,
-                                     cursorInfo.lineHeight );
+                                     cursorInfo.lineHeight);
 
   // If selection handle at start of the text and other at end of the text then all text is selected.
-  const CharacterIndex startOfSelection = std::min( eventData->mLeftSelectionPosition, eventData->mRightSelectionPosition );
-  const CharacterIndex endOfSelection = std::max ( eventData->mLeftSelectionPosition, eventData->mRightSelectionPosition );
-  eventData->mAllTextSelected = ( startOfSelection == 0 ) && ( endOfSelection == model->mLogicalModel->mText.Count() );
+  const CharacterIndex startOfSelection = std::min(eventData->mLeftSelectionPosition, eventData->mRightSelectionPosition);
+  const CharacterIndex endOfSelection   = std::max(eventData->mLeftSelectionPosition, eventData->mRightSelectionPosition);
+  eventData->mAllTextSelected           = (startOfSelection == 0) && (endOfSelection == model->mLogicalModel->mText.Count());
 }
 
 } // namespace Text