Add post processor
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-selection-handle-controller.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/text/text-selection-handle-controller.h>
20
21 #include <dali/integration-api/debug.h>
22 #include <limits>
23
24 // INTERNAL INCLUDES
25 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
26 #include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
27
28 using namespace Dali;
29
30 namespace
31 {
32 /**
33  * @brief Struct used to calculate the selection box.
34  */
35 struct SelectionBoxInfo
36 {
37   float lineOffset;
38   float lineHeight;
39   float minX;
40   float maxX;
41 };
42
43 #if defined(DEBUG_ENABLED)
44 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
45 #endif
46
47 const float                                   MAX_FLOAT = std::numeric_limits<float>::max();
48 const float                                   MIN_FLOAT = std::numeric_limits<float>::min();
49 const Dali::Toolkit::Text::CharacterDirection LTR       = false; ///< Left To Right direction
50
51 } // namespace
52
53 namespace Dali
54 {
55 namespace Toolkit
56 {
57 namespace Text
58 {
59 void SelectionHandleController::Reposition(Controller::Impl& impl)
60 {
61   EventData*& eventData = impl.mEventData;
62
63   CharacterIndex selectionStart = eventData->mLeftSelectionPosition;
64   CharacterIndex selectionEnd   = eventData->mRightSelectionPosition;
65
66   DecoratorPtr& decorator = eventData->mDecorator;
67
68   if(selectionStart == selectionEnd)
69   {
70     // Nothing to select if handles are in the same place.
71     // So, deactive Highlight box.
72     decorator->SetHighlightActive(false);
73     return;
74   }
75
76   decorator->ClearHighlights();
77
78   ModelPtr&        model        = impl.mModel;
79   VisualModelPtr&  visualModel  = model->mVisualModel;
80   LogicalModelPtr& logicalModel = model->mLogicalModel;
81
82   const GlyphIndex* const         charactersToGlyphBuffer        = visualModel->mCharactersToGlyph.Begin();
83   const Length* const             glyphsPerCharacterBuffer       = visualModel->mGlyphsPerCharacter.Begin();
84   const GlyphInfo* const          glyphsBuffer                   = visualModel->mGlyphs.Begin();
85   const Vector2* const            positionsBuffer                = visualModel->mGlyphPositions.Begin();
86   const Length* const             charactersPerGlyphBuffer       = visualModel->mCharactersPerGlyph.Begin();
87   const CharacterIndex* const     glyphToCharacterBuffer         = visualModel->mGlyphsToCharacters.Begin();
88   const CharacterDirection* const modelCharacterDirectionsBuffer = (0u != logicalModel->mCharacterDirections.Count()) ? logicalModel->mCharacterDirections.Begin() : NULL;
89
90   const bool               isLastCharacter = selectionEnd >= logicalModel->mText.Count();
91   const CharacterDirection startDirection  = ((NULL == modelCharacterDirectionsBuffer) ? false : *(modelCharacterDirectionsBuffer + selectionStart));
92   const CharacterDirection endDirection    = ((NULL == modelCharacterDirectionsBuffer) ? false : *(modelCharacterDirectionsBuffer + (selectionEnd - (isLastCharacter ? 1u : 0u))));
93
94   // Swap the indices if the start is greater than the end.
95   const bool indicesSwapped = selectionStart > selectionEnd;
96
97   // Tell the decorator to flip the selection handles if needed.
98   decorator->SetSelectionHandleFlipState(indicesSwapped, startDirection, endDirection);
99
100   if(indicesSwapped)
101   {
102     std::swap(selectionStart, selectionEnd);
103   }
104
105   // Get the indices to the first and last selected glyphs.
106   const CharacterIndex selectionEndMinusOne = selectionEnd - 1u;
107   const GlyphIndex     glyphStart           = *(charactersToGlyphBuffer + selectionStart);
108   const Length         numberOfGlyphs       = *(glyphsPerCharacterBuffer + selectionEndMinusOne);
109   const GlyphIndex     glyphEnd             = *(charactersToGlyphBuffer + selectionEndMinusOne) + ((numberOfGlyphs > 0) ? numberOfGlyphs - 1u : 0u);
110
111   // Get the lines where the glyphs are laid-out.
112   const LineRun* lineRun = visualModel->mLines.Begin();
113
114   LineIndex lineIndex     = 0u;
115   Length    numberOfLines = 0u;
116   visualModel->GetNumberOfLines(glyphStart,
117                                 1u + glyphEnd - glyphStart,
118                                 lineIndex,
119                                 numberOfLines);
120   const LineIndex firstLineIndex = lineIndex;
121
122   // Create the structure to store some selection box info.
123   Vector<SelectionBoxInfo> selectionBoxLinesInfo;
124   selectionBoxLinesInfo.Resize(numberOfLines);
125
126   SelectionBoxInfo* selectionBoxInfo = selectionBoxLinesInfo.Begin();
127   selectionBoxInfo->minX             = MAX_FLOAT;
128   selectionBoxInfo->maxX             = MIN_FLOAT;
129
130   // Keep the min and max 'x' position to calculate the size and position of the highlighed text.
131   float   minHighlightX = std::numeric_limits<float>::max();
132   float   maxHighlightX = std::numeric_limits<float>::min();
133   Size    highLightSize;
134   Vector2 highLightPosition; // The highlight position in decorator's coords.
135
136   // Retrieve the first line and get the line's vertical offset, the line's height and the index to the last glyph.
137
138   // The line's vertical offset of all the lines before the line where the first glyph is laid-out.
139   selectionBoxInfo->lineOffset = CalculateLineOffset(visualModel->mLines,
140                                                      firstLineIndex);
141
142   // Transform to decorator's (control) coords.
143   selectionBoxInfo->lineOffset += model->mScrollPosition.y;
144
145   lineRun += firstLineIndex;
146
147   // The line height is the addition of the line ascender and the line descender.
148   // However, the line descender has a negative value, hence the subtraction.
149   selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
150
151   GlyphIndex lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
152
153   // Check if the first glyph is a ligature that must be broken like Latin ff, fi, or Arabic ﻻ, etc which needs special code.
154   const Length numberOfCharactersStart = *(charactersPerGlyphBuffer + glyphStart);
155   bool         splitStartGlyph         = (numberOfCharactersStart > 1u) && HasLigatureMustBreak(logicalModel->GetScript(selectionStart));
156
157   // Check if the last glyph is a ligature that must be broken like Latin ff, fi, or Arabic ﻻ, etc which needs special code.
158   const Length numberOfCharactersEnd = *(charactersPerGlyphBuffer + glyphEnd);
159   bool         splitEndGlyph         = (glyphStart != glyphEnd) && (numberOfCharactersEnd > 1u) && HasLigatureMustBreak(logicalModel->GetScript(selectionEndMinusOne));
160
161   // The number of quads of the selection box.
162   const unsigned int numberOfQuads = 1u + (glyphEnd - glyphStart) + ((numberOfLines > 1u) ? 2u * numberOfLines : 0u);
163   decorator->ResizeHighlightQuads(numberOfQuads);
164
165   // Count the actual number of quads.
166   unsigned int actualNumberOfQuads = 0u;
167   Vector4      quad;
168
169   // Traverse the glyphs.
170   for(GlyphIndex index = glyphStart; index <= glyphEnd; ++index)
171   {
172     const GlyphInfo& glyph    = *(glyphsBuffer + index);
173     const Vector2&   position = *(positionsBuffer + index);
174
175     if(splitStartGlyph)
176     {
177       // 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.
178
179       const float          glyphAdvance    = glyph.advance / static_cast<float>(numberOfCharactersStart);
180       const CharacterIndex interGlyphIndex = selectionStart - *(glyphToCharacterBuffer + glyphStart);
181       // Get the direction of the character.
182       CharacterDirection isCurrentRightToLeft = false;
183       if(nullptr != modelCharacterDirectionsBuffer) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
184       {
185         isCurrentRightToLeft = *(modelCharacterDirectionsBuffer + selectionStart);
186       }
187
188       // The end point could be in the middle of the ligature.
189       // Calculate the number of characters selected.
190       const Length numberOfCharacters = (glyphStart == glyphEnd) ? (selectionEnd - selectionStart) : (numberOfCharactersStart - interGlyphIndex);
191
192       quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + model->mScrollPosition.x + glyphAdvance * static_cast<float>(isCurrentRightToLeft ? (numberOfCharactersStart - interGlyphIndex - numberOfCharacters) : interGlyphIndex);
193       quad.y = selectionBoxInfo->lineOffset;
194       quad.z = quad.x + static_cast<float>(numberOfCharacters) * glyphAdvance;
195       quad.w = selectionBoxInfo->lineOffset + selectionBoxInfo->lineHeight;
196
197       // Store the min and max 'x' for each line.
198       selectionBoxInfo->minX = std::min(selectionBoxInfo->minX, quad.x);
199       selectionBoxInfo->maxX = std::max(selectionBoxInfo->maxX, quad.z);
200
201       decorator->AddHighlight(actualNumberOfQuads, quad);
202       ++actualNumberOfQuads;
203
204       splitStartGlyph = false;
205       continue;
206     }
207
208     if(splitEndGlyph && (index == glyphEnd))
209     {
210       // 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.
211
212       const float          glyphAdvance    = glyph.advance / static_cast<float>(numberOfCharactersEnd);
213       const CharacterIndex interGlyphIndex = selectionEnd - *(glyphToCharacterBuffer + glyphEnd);
214       // Get the direction of the character.
215       CharacterDirection isCurrentRightToLeft = false;
216       if(nullptr != modelCharacterDirectionsBuffer) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
217       {
218         isCurrentRightToLeft = *(modelCharacterDirectionsBuffer + selectionEnd);
219       }
220
221       const Length numberOfCharacters = numberOfCharactersEnd - interGlyphIndex;
222
223       quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + model->mScrollPosition.x + (isCurrentRightToLeft ? (glyphAdvance * static_cast<float>(numberOfCharacters)) : 0.f);
224       quad.y = selectionBoxInfo->lineOffset;
225       quad.z = quad.x + static_cast<float>(interGlyphIndex) * glyphAdvance;
226       quad.w = quad.y + selectionBoxInfo->lineHeight;
227
228       // Store the min and max 'x' for each line.
229       selectionBoxInfo->minX = std::min(selectionBoxInfo->minX, quad.x);
230       selectionBoxInfo->maxX = std::max(selectionBoxInfo->maxX, quad.z);
231
232       decorator->AddHighlight(actualNumberOfQuads,
233                               quad);
234       ++actualNumberOfQuads;
235
236       splitEndGlyph = false;
237       continue;
238     }
239
240     quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + model->mScrollPosition.x;
241     quad.y = selectionBoxInfo->lineOffset;
242     quad.z = quad.x + glyph.advance;
243     quad.w = quad.y + selectionBoxInfo->lineHeight;
244
245     // Store the min and max 'x' for each line.
246     selectionBoxInfo->minX = std::min(selectionBoxInfo->minX, quad.x);
247     selectionBoxInfo->maxX = std::max(selectionBoxInfo->maxX, quad.z);
248
249     decorator->AddHighlight(actualNumberOfQuads,
250                             quad);
251     ++actualNumberOfQuads;
252
253     // Whether to retrieve the next line.
254     if(index == lastGlyphOfLine)
255     {
256       ++lineIndex;
257       if(lineIndex < firstLineIndex + numberOfLines)
258       {
259         // Retrieve the next line.
260         ++lineRun;
261
262         // Get the last glyph of the new line.
263         lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
264
265         // Keep the offset and height of the current selection box.
266         const float currentLineOffset = selectionBoxInfo->lineOffset;
267         const float currentLineHeight = selectionBoxInfo->lineHeight;
268
269         // Get the selection box info for the next line.
270         ++selectionBoxInfo;
271
272         selectionBoxInfo->minX = MAX_FLOAT;
273         selectionBoxInfo->maxX = MIN_FLOAT;
274
275         // Update the line's vertical offset.
276         selectionBoxInfo->lineOffset = currentLineOffset + currentLineHeight;
277
278         // The line height is the addition of the line ascender and the line descender.
279         // However, the line descender has a negative value, hence the subtraction.
280         selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
281       }
282     }
283   }
284
285   // Traverses all the lines and updates the min and max 'x' positions and the total height.
286   // The final width is calculated after 'boxifying' the selection.
287   for(Vector<SelectionBoxInfo>::ConstIterator it    = selectionBoxLinesInfo.Begin(),
288                                               endIt = selectionBoxLinesInfo.End();
289       it != endIt;
290       ++it)
291   {
292     const SelectionBoxInfo& info = *it;
293
294     // Update the size of the highlighted text.
295     highLightSize.height += info.lineHeight;
296     minHighlightX = std::min(minHighlightX, info.minX);
297     maxHighlightX = std::max(maxHighlightX, info.maxX);
298   }
299
300   // Add extra geometry to 'boxify' the selection.
301
302   if(1u < numberOfLines)
303   {
304     // Boxify the first line.
305     lineRun                                           = visualModel->mLines.Begin() + firstLineIndex;
306     const SelectionBoxInfo& firstSelectionBoxLineInfo = *(selectionBoxLinesInfo.Begin());
307
308     bool boxifyBegin = (LTR != lineRun->direction) && (LTR != startDirection);
309     bool boxifyEnd   = (LTR == lineRun->direction) && (LTR == startDirection);
310
311     if(boxifyBegin)
312     {
313       quad.x = 0.f;
314       quad.y = firstSelectionBoxLineInfo.lineOffset;
315       quad.z = firstSelectionBoxLineInfo.minX;
316       quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
317
318       // Boxify at the beginning of the line.
319       decorator->AddHighlight(actualNumberOfQuads,
320                               quad);
321       ++actualNumberOfQuads;
322
323       // Update the size of the highlighted text.
324       minHighlightX = 0.f;
325     }
326
327     if(boxifyEnd)
328     {
329       quad.x = firstSelectionBoxLineInfo.maxX;
330       quad.y = firstSelectionBoxLineInfo.lineOffset;
331       quad.z = visualModel->mControlSize.width;
332       quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
333
334       // Boxify at the end of the line.
335       decorator->AddHighlight(actualNumberOfQuads,
336                               quad);
337       ++actualNumberOfQuads;
338
339       // Update the size of the highlighted text.
340       maxHighlightX = visualModel->mControlSize.width;
341     }
342
343     // Boxify the central lines.
344     if(2u < numberOfLines)
345     {
346       for(Vector<SelectionBoxInfo>::ConstIterator it    = selectionBoxLinesInfo.Begin() + 1u,
347                                                   endIt = selectionBoxLinesInfo.End() - 1u;
348           it != endIt;
349           ++it)
350       {
351         const SelectionBoxInfo& info = *it;
352
353         quad.x = 0.f;
354         quad.y = info.lineOffset;
355         quad.z = info.minX;
356         quad.w = info.lineOffset + info.lineHeight;
357
358         decorator->AddHighlight(actualNumberOfQuads,
359                                 quad);
360         ++actualNumberOfQuads;
361
362         quad.x = info.maxX;
363         quad.y = info.lineOffset;
364         quad.z = visualModel->mControlSize.width;
365         quad.w = info.lineOffset + info.lineHeight;
366
367         decorator->AddHighlight(actualNumberOfQuads,
368                                 quad);
369         ++actualNumberOfQuads;
370       }
371
372       // Update the size of the highlighted text.
373       minHighlightX = 0.f;
374       maxHighlightX = visualModel->mControlSize.width;
375     }
376
377     // Boxify the last line.
378     lineRun                                          = visualModel->mLines.Begin() + firstLineIndex + numberOfLines - 1u;
379     const SelectionBoxInfo& lastSelectionBoxLineInfo = *(selectionBoxLinesInfo.End() - 1u);
380
381     boxifyBegin = (LTR == lineRun->direction) && (LTR == endDirection);
382     boxifyEnd   = (LTR != lineRun->direction) && (LTR != endDirection);
383
384     if(boxifyBegin)
385     {
386       quad.x = 0.f;
387       quad.y = lastSelectionBoxLineInfo.lineOffset;
388       quad.z = lastSelectionBoxLineInfo.minX;
389       quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
390
391       // Boxify at the beginning of the line.
392       decorator->AddHighlight(actualNumberOfQuads,
393                               quad);
394       ++actualNumberOfQuads;
395
396       // Update the size of the highlighted text.
397       minHighlightX = 0.f;
398     }
399
400     if(boxifyEnd)
401     {
402       quad.x = lastSelectionBoxLineInfo.maxX;
403       quad.y = lastSelectionBoxLineInfo.lineOffset;
404       quad.z = visualModel->mControlSize.width;
405       quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
406
407       // Boxify at the end of the line.
408       decorator->AddHighlight(actualNumberOfQuads, quad);
409       ++actualNumberOfQuads;
410
411       // Update the size of the highlighted text.
412       maxHighlightX = visualModel->mControlSize.width;
413     }
414   }
415
416   // Set the actual number of quads.
417   decorator->ResizeHighlightQuads(actualNumberOfQuads);
418
419   // Sets the highlight's size and position. In decorator's coords.
420   // The highlight's height has been calculated above (before 'boxifying' the highlight).
421   highLightSize.width = maxHighlightX - minHighlightX;
422
423   highLightPosition.x                               = minHighlightX;
424   const SelectionBoxInfo& firstSelectionBoxLineInfo = *(selectionBoxLinesInfo.Begin());
425   highLightPosition.y                               = firstSelectionBoxLineInfo.lineOffset;
426
427   decorator->SetHighLightBox(highLightPosition, highLightSize, static_cast<float>(model->GetOutlineWidth()));
428
429   if(!decorator->IsSmoothHandlePanEnabled())
430   {
431     CursorInfo primaryCursorInfo;
432     impl.GetCursorPosition(eventData->mLeftSelectionPosition, primaryCursorInfo);
433
434     const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + model->mScrollPosition;
435
436     decorator->SetPosition(LEFT_SELECTION_HANDLE,
437                            primaryPosition.x,
438                            primaryCursorInfo.lineOffset + model->mScrollPosition.y,
439                            primaryCursorInfo.lineHeight);
440
441     CursorInfo secondaryCursorInfo;
442     impl.GetCursorPosition(eventData->mRightSelectionPosition, secondaryCursorInfo);
443
444     const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + model->mScrollPosition;
445
446     decorator->SetPosition(RIGHT_SELECTION_HANDLE,
447                            secondaryPosition.x,
448                            secondaryCursorInfo.lineOffset + model->mScrollPosition.y,
449                            secondaryCursorInfo.lineHeight);
450   }
451
452   // Set the flag to update the decorator.
453   eventData->mDecoratorUpdated = true;
454 }
455
456 void SelectionHandleController::Reposition(Controller::Impl& impl, float visualX, float visualY, Controller::NoTextTap::Action action)
457 {
458   EventData*& eventData = impl.mEventData;
459   if(nullptr == eventData)
460   {
461     // Nothing to do if there is no text input.
462     return;
463   }
464
465   if(impl.IsShowingPlaceholderText())
466   {
467     // Nothing to do if there is the place-holder text.
468     return;
469   }
470
471   ModelPtr&       model          = impl.mModel;
472   VisualModelPtr& visualModel    = model->mVisualModel;
473   const Length    numberOfGlyphs = visualModel->mGlyphs.Count();
474   const Length    numberOfLines  = visualModel->mLines.Count();
475   if((0 == numberOfGlyphs) ||
476      (0 == numberOfLines))
477   {
478     // Nothing to do if there is no text.
479     return;
480   }
481
482   // Find which word was selected
483   CharacterIndex selectionStart(0);
484   CharacterIndex selectionEnd(0);
485   CharacterIndex noTextHitIndex(0);
486   const bool     characterHit = FindSelectionIndices(visualModel,
487                                                  model->mLogicalModel,
488                                                  impl.mMetrics,
489                                                  visualX,
490                                                  visualY,
491                                                  selectionStart,
492                                                  selectionEnd,
493                                                  noTextHitIndex);
494   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", &impl, selectionStart, selectionEnd);
495
496   if(characterHit || (Controller::NoTextTap::HIGHLIGHT == action))
497   {
498     impl.ChangeState(EventData::SELECTING);
499
500     eventData->mLeftSelectionPosition  = selectionStart;
501     eventData->mRightSelectionPosition = selectionEnd;
502
503     eventData->mUpdateLeftSelectionPosition  = true;
504     eventData->mUpdateRightSelectionPosition = true;
505     eventData->mUpdateHighlightBox           = true;
506
507     // It may happen an InputMethodContext commit event arrives before the selection event
508     // if the InputMethodContext is in pre-edit state. The commit event will set the
509     // eventData->mUpdateCursorPosition flag to true. If it's not set back
510     // to false, the highlight box won't be updated.
511     eventData->mUpdateCursorPosition = false;
512
513     eventData->mScrollAfterUpdatePosition = (eventData->mLeftSelectionPosition != eventData->mRightSelectionPosition);
514
515     // Cursor to be positioned at end of selection so if selection interrupted and edit mode restarted the cursor will be at end of selection
516     eventData->mPrimaryCursorPosition = std::max(eventData->mLeftSelectionPosition, eventData->mRightSelectionPosition);
517   }
518   else if(Controller::NoTextTap::SHOW_SELECTION_POPUP == action)
519   {
520     // Nothing to select. i.e. a white space, out of bounds
521     impl.ChangeState(EventData::EDITING_WITH_POPUP);
522
523     eventData->mPrimaryCursorPosition = noTextHitIndex;
524
525     eventData->mUpdateCursorPosition      = true;
526     eventData->mUpdateGrabHandlePosition  = true;
527     eventData->mScrollAfterUpdatePosition = true;
528     eventData->mUpdateInputStyle          = true;
529   }
530   else if(Controller::NoTextTap::NO_ACTION == action)
531   {
532     // Nothing to select. i.e. a white space, out of bounds
533     eventData->mPrimaryCursorPosition = noTextHitIndex;
534
535     eventData->mUpdateCursorPosition      = true;
536     eventData->mUpdateGrabHandlePosition  = true;
537     eventData->mScrollAfterUpdatePosition = true;
538     eventData->mUpdateInputStyle          = true;
539   }
540 }
541
542 void SelectionHandleController::Update(Controller::Impl& impl, HandleType handleType, const CursorInfo& cursorInfo)
543 {
544   if((LEFT_SELECTION_HANDLE != handleType) &&
545      (RIGHT_SELECTION_HANDLE != handleType))
546   {
547     return;
548   }
549
550   ModelPtr&     model          = impl.mModel;
551   const Vector2 cursorPosition = cursorInfo.primaryPosition + model->mScrollPosition;
552
553   // Sets the handle's position.
554   EventData*& eventData = impl.mEventData;
555   eventData->mDecorator->SetPosition(handleType,
556                                      cursorPosition.x,
557                                      cursorInfo.lineOffset + model->mScrollPosition.y,
558                                      cursorInfo.lineHeight);
559
560   // If selection handle at start of the text and other at end of the text then all text is selected.
561   const CharacterIndex startOfSelection = std::min(eventData->mLeftSelectionPosition, eventData->mRightSelectionPosition);
562   const CharacterIndex endOfSelection   = std::max(eventData->mLeftSelectionPosition, eventData->mRightSelectionPosition);
563   eventData->mAllTextSelected           = (startOfSelection == 0) && (endOfSelection == model->mLogicalModel->mText.Count());
564 }
565
566 } // namespace Text
567
568 } // namespace Toolkit
569
570 } // namespace Dali