6a90595738171d52652d0762a4307f9e6661d973
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-impl.cpp
1 /*
2  * Copyright (c) 2017 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-controller-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/adaptor-framework/key.h>
23 #include <dali/integration-api/debug.h>
24 #include <limits>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/internal/text/bidirectional-support.h>
28 #include <dali-toolkit/internal/text/character-set-conversion.h>
29 #include <dali-toolkit/internal/text/color-segmentation.h>
30 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
31 #include <dali-toolkit/internal/text/multi-language-support.h>
32 #include <dali-toolkit/internal/text/segmentation.h>
33 #include <dali-toolkit/internal/text/shaper.h>
34 #include <dali-toolkit/internal/text/text-control-interface.h>
35 #include <dali-toolkit/internal/text/text-run-container.h>
36
37 namespace
38 {
39
40 /**
41  * @brief Struct used to calculate the selection box.
42  */
43 struct SelectionBoxInfo
44 {
45   float lineOffset;
46   float lineHeight;
47   float minX;
48   float maxX;
49 };
50
51 #if defined(DEBUG_ENABLED)
52   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
53 #endif
54
55 const float MAX_FLOAT = std::numeric_limits<float>::max();
56 const float MIN_FLOAT = std::numeric_limits<float>::min();
57 const Dali::Toolkit::Text::CharacterDirection LTR = false; ///< Left To Right direction
58
59 } // namespace
60
61 namespace Dali
62 {
63
64 namespace Toolkit
65 {
66
67 namespace Text
68 {
69
70 EventData::EventData( DecoratorPtr decorator )
71 : mDecorator( decorator ),
72   mImfManager(),
73   mPlaceholderFont( NULL ),
74   mPlaceholderText(),
75   mPlaceholderTextActive(),
76   mPlaceholderTextInactive(),
77   mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ),
78   mEventQueue(),
79   mInputStyleChangedQueue(),
80   mPreviousState( INACTIVE ),
81   mState( INACTIVE ),
82   mPrimaryCursorPosition( 0u ),
83   mLeftSelectionPosition( 0u ),
84   mRightSelectionPosition( 0u ),
85   mPreEditStartPosition( 0u ),
86   mPreEditLength( 0u ),
87   mCursorHookPositionX( 0.f ),
88   mDoubleTapAction( Controller::NoTextTap::NO_ACTION ),
89   mLongPressAction( Controller::NoTextTap::SHOW_SELECTION_POPUP ),
90   mIsShowingPlaceholderText( false ),
91   mPreEditFlag( false ),
92   mDecoratorUpdated( false ),
93   mCursorBlinkEnabled( true ),
94   mGrabHandleEnabled( true ),
95   mGrabHandlePopupEnabled( true ),
96   mSelectionEnabled( true ),
97   mUpdateCursorHookPosition( false ),
98   mUpdateCursorPosition( false ),
99   mUpdateGrabHandlePosition( false ),
100   mUpdateLeftSelectionPosition( false ),
101   mUpdateRightSelectionPosition( false ),
102   mIsLeftHandleSelected( false ),
103   mIsRightHandleSelected( false ),
104   mUpdateHighlightBox( false ),
105   mScrollAfterUpdatePosition( false ),
106   mScrollAfterDelete( false ),
107   mAllTextSelected( false ),
108   mUpdateInputStyle( false ),
109   mPasswordInput( false ),
110   mIsPlaceholderPixelSize( false )
111 {
112   mImfManager = ImfManager::Get();
113 }
114
115 EventData::~EventData()
116 {}
117
118 bool Controller::Impl::ProcessInputEvents()
119 {
120   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::ProcessInputEvents\n" );
121   if( NULL == mEventData )
122   {
123     // Nothing to do if there is no text input.
124     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents no event data\n" );
125     return false;
126   }
127
128   if( mEventData->mDecorator )
129   {
130     for( std::vector<Event>::iterator iter = mEventData->mEventQueue.begin();
131          iter != mEventData->mEventQueue.end();
132          ++iter )
133     {
134       switch( iter->type )
135       {
136         case Event::CURSOR_KEY_EVENT:
137         {
138           OnCursorKeyEvent( *iter );
139           break;
140         }
141         case Event::TAP_EVENT:
142         {
143           OnTapEvent( *iter );
144           break;
145         }
146         case Event::LONG_PRESS_EVENT:
147         {
148           OnLongPressEvent( *iter );
149           break;
150         }
151         case Event::PAN_EVENT:
152         {
153           OnPanEvent( *iter );
154           break;
155         }
156         case Event::GRAB_HANDLE_EVENT:
157         case Event::LEFT_SELECTION_HANDLE_EVENT:
158         case Event::RIGHT_SELECTION_HANDLE_EVENT: // Fall through
159         {
160           OnHandleEvent( *iter );
161           break;
162         }
163         case Event::SELECT:
164         {
165           OnSelectEvent( *iter );
166           break;
167         }
168         case Event::SELECT_ALL:
169         {
170           OnSelectAllEvent();
171           break;
172         }
173       }
174     }
175   }
176
177   if( mEventData->mUpdateCursorPosition ||
178       mEventData->mUpdateHighlightBox )
179   {
180     NotifyImfManager();
181   }
182
183   // The cursor must also be repositioned after inserts into the model
184   if( mEventData->mUpdateCursorPosition )
185   {
186     // Updates the cursor position and scrolls the text to make it visible.
187     CursorInfo cursorInfo;
188     // Calculate the cursor position from the new cursor index.
189     GetCursorPosition( mEventData->mPrimaryCursorPosition,
190                        cursorInfo );
191
192     if( mEventData->mUpdateCursorHookPosition )
193     {
194       // Update the cursor hook position. Used to move the cursor with the keys 'up' and 'down'.
195       mEventData->mCursorHookPositionX = cursorInfo.primaryPosition.x;
196       mEventData->mUpdateCursorHookPosition = false;
197     }
198
199     // Scroll first the text after delete ...
200     if( mEventData->mScrollAfterDelete )
201     {
202       ScrollTextToMatchCursor( cursorInfo );
203     }
204
205     // ... then, text can be scrolled to make the cursor visible.
206     if( mEventData->mScrollAfterUpdatePosition )
207     {
208       const Vector2 currentCursorPosition( cursorInfo.primaryPosition.x, cursorInfo.lineOffset );
209       ScrollToMakePositionVisible( currentCursorPosition, cursorInfo.lineHeight );
210     }
211     mEventData->mScrollAfterUpdatePosition = false;
212     mEventData->mScrollAfterDelete = false;
213
214     UpdateCursorPosition( cursorInfo );
215
216     mEventData->mDecoratorUpdated = true;
217     mEventData->mUpdateCursorPosition = false;
218     mEventData->mUpdateGrabHandlePosition = false;
219   }
220   else
221   {
222     CursorInfo leftHandleInfo;
223     CursorInfo rightHandleInfo;
224
225     if( mEventData->mUpdateHighlightBox )
226     {
227       GetCursorPosition( mEventData->mLeftSelectionPosition,
228                          leftHandleInfo );
229
230       GetCursorPosition( mEventData->mRightSelectionPosition,
231                          rightHandleInfo );
232
233       if( mEventData->mScrollAfterUpdatePosition && ( mEventData->mIsLeftHandleSelected ? mEventData->mUpdateLeftSelectionPosition : mEventData->mUpdateRightSelectionPosition ) )
234       {
235         if( mEventData->mIsLeftHandleSelected && mEventData->mIsRightHandleSelected )
236         {
237           CursorInfo& infoLeft = leftHandleInfo;
238
239           const Vector2 currentCursorPositionLeft( infoLeft.primaryPosition.x, infoLeft.lineOffset );
240           ScrollToMakePositionVisible( currentCursorPositionLeft, infoLeft.lineHeight );
241
242           CursorInfo& infoRight = rightHandleInfo;
243
244           const Vector2 currentCursorPositionRight( infoRight.primaryPosition.x, infoRight.lineOffset );
245           ScrollToMakePositionVisible( currentCursorPositionRight, infoRight.lineHeight );
246         }
247         else
248         {
249           CursorInfo& info = mEventData->mIsLeftHandleSelected ? leftHandleInfo : rightHandleInfo;
250
251           const Vector2 currentCursorPosition( info.primaryPosition.x, info.lineOffset );
252           ScrollToMakePositionVisible( currentCursorPosition, info.lineHeight );
253         }
254       }
255     }
256
257     if( mEventData->mUpdateLeftSelectionPosition )
258     {
259       UpdateSelectionHandle( LEFT_SELECTION_HANDLE,
260                              leftHandleInfo );
261
262       SetPopupButtons();
263       mEventData->mDecoratorUpdated = true;
264       mEventData->mUpdateLeftSelectionPosition = false;
265     }
266
267     if( mEventData->mUpdateRightSelectionPosition )
268     {
269       UpdateSelectionHandle( RIGHT_SELECTION_HANDLE,
270                              rightHandleInfo );
271
272       SetPopupButtons();
273       mEventData->mDecoratorUpdated = true;
274       mEventData->mUpdateRightSelectionPosition = false;
275     }
276
277     if( mEventData->mUpdateHighlightBox )
278     {
279       RepositionSelectionHandles();
280
281       mEventData->mUpdateLeftSelectionPosition = false;
282       mEventData->mUpdateRightSelectionPosition = false;
283       mEventData->mUpdateHighlightBox = false;
284       mEventData->mIsLeftHandleSelected = false;
285       mEventData->mIsRightHandleSelected = false;
286     }
287
288     mEventData->mScrollAfterUpdatePosition = false;
289   }
290
291   if( mEventData->mUpdateInputStyle )
292   {
293     // Keep a copy of the current input style.
294     InputStyle currentInputStyle;
295     currentInputStyle.Copy( mEventData->mInputStyle );
296
297     // Set the default style first.
298     RetrieveDefaultInputStyle( mEventData->mInputStyle );
299
300     // Get the character index from the cursor index.
301     const CharacterIndex styleIndex = ( mEventData->mPrimaryCursorPosition > 0u ) ? mEventData->mPrimaryCursorPosition - 1u : 0u;
302
303     // Retrieve the style from the style runs stored in the logical model.
304     mModel->mLogicalModel->RetrieveStyle( styleIndex, mEventData->mInputStyle );
305
306     // Compare if the input style has changed.
307     const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle );
308
309     if( hasInputStyleChanged )
310     {
311       const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle );
312       // Queue the input style changed signal.
313       mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
314     }
315
316     mEventData->mUpdateInputStyle = false;
317   }
318
319   mEventData->mEventQueue.clear();
320
321   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n" );
322
323   const bool decoratorUpdated = mEventData->mDecoratorUpdated;
324   mEventData->mDecoratorUpdated = false;
325
326   return decoratorUpdated;
327 }
328
329 void Controller::Impl::NotifyImfManager()
330 {
331   if( mEventData && mEventData->mImfManager )
332   {
333     CharacterIndex cursorPosition = GetLogicalCursorPosition();
334
335     const Length numberOfWhiteSpaces = GetNumberOfWhiteSpaces( 0u );
336
337     // Update the cursor position by removing the initial white spaces.
338     if( cursorPosition < numberOfWhiteSpaces )
339     {
340       cursorPosition = 0u;
341     }
342     else
343     {
344       cursorPosition -= numberOfWhiteSpaces;
345     }
346
347     mEventData->mImfManager.SetCursorPosition( cursorPosition );
348     mEventData->mImfManager.NotifyCursorPosition();
349   }
350 }
351
352 void Controller::Impl::NotifyImfMultiLineStatus()
353 {
354   if ( mEventData )
355   {
356     Text::Layout::Engine::Type layout = mLayoutEngine.GetLayout();
357     mEventData->mImfManager.NotifyTextInputMultiLine( layout == Text::Layout::Engine::MULTI_LINE_BOX );
358   }
359 }
360
361 CharacterIndex Controller::Impl::GetLogicalCursorPosition() const
362 {
363   CharacterIndex cursorPosition = 0u;
364
365   if( mEventData )
366   {
367     if( ( EventData::SELECTING == mEventData->mState ) ||
368         ( EventData::SELECTION_HANDLE_PANNING == mEventData->mState ) )
369     {
370       cursorPosition = std::min( mEventData->mRightSelectionPosition, mEventData->mLeftSelectionPosition );
371     }
372     else
373     {
374       cursorPosition = mEventData->mPrimaryCursorPosition;
375     }
376   }
377
378   return cursorPosition;
379 }
380
381 Length Controller::Impl::GetNumberOfWhiteSpaces( CharacterIndex index ) const
382 {
383   Length numberOfWhiteSpaces = 0u;
384
385   // Get the buffer to the text.
386   Character* utf32CharacterBuffer = mModel->mLogicalModel->mText.Begin();
387
388   const Length totalNumberOfCharacters = mModel->mLogicalModel->mText.Count();
389   for( ; index < totalNumberOfCharacters; ++index, ++numberOfWhiteSpaces )
390   {
391     if( !TextAbstraction::IsWhiteSpace( *( utf32CharacterBuffer + index ) ) )
392     {
393       break;
394     }
395   }
396
397   return numberOfWhiteSpaces;
398 }
399
400 void Controller::Impl::GetText( CharacterIndex index, std::string& text ) const
401 {
402   // Get the total number of characters.
403   Length numberOfCharacters = mModel->mLogicalModel->mText.Count();
404
405   // Retrieve the text.
406   if( 0u != numberOfCharacters )
407   {
408     Utf32ToUtf8( mModel->mLogicalModel->mText.Begin() + index, numberOfCharacters - index, text );
409   }
410 }
411
412 void Controller::Impl::CalculateTextUpdateIndices( Length& numberOfCharacters )
413 {
414   mTextUpdateInfo.mParagraphCharacterIndex = 0u;
415   mTextUpdateInfo.mStartGlyphIndex = 0u;
416   mTextUpdateInfo.mStartLineIndex = 0u;
417   numberOfCharacters = 0u;
418
419   const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
420   if( 0u == numberOfParagraphs )
421   {
422     mTextUpdateInfo.mParagraphCharacterIndex = 0u;
423     numberOfCharacters = 0u;
424
425     mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
426
427     // Nothing else to do if there are no paragraphs.
428     return;
429   }
430
431   // Find the paragraphs to be updated.
432   Vector<ParagraphRunIndex> paragraphsToBeUpdated;
433   if( mTextUpdateInfo.mCharacterIndex >= mTextUpdateInfo.mPreviousNumberOfCharacters )
434   {
435     // Text is being added at the end of the current text.
436     if( mTextUpdateInfo.mIsLastCharacterNewParagraph )
437     {
438       // Text is being added in a new paragraph after the last character of the text.
439       mTextUpdateInfo.mParagraphCharacterIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
440       numberOfCharacters = 0u;
441       mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
442
443       mTextUpdateInfo.mStartGlyphIndex = mModel->mVisualModel->mGlyphs.Count();
444       mTextUpdateInfo.mStartLineIndex = mModel->mVisualModel->mLines.Count() - 1u;
445
446       // Nothing else to do;
447       return;
448     }
449
450     paragraphsToBeUpdated.PushBack( numberOfParagraphs - 1u );
451   }
452   else
453   {
454     Length numberOfCharactersToUpdate = 0u;
455     if( mTextUpdateInfo.mFullRelayoutNeeded )
456     {
457       numberOfCharactersToUpdate = mTextUpdateInfo.mPreviousNumberOfCharacters;
458     }
459     else
460     {
461       numberOfCharactersToUpdate = ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
462     }
463     mModel->mLogicalModel->FindParagraphs( mTextUpdateInfo.mCharacterIndex,
464                                            numberOfCharactersToUpdate,
465                                            paragraphsToBeUpdated );
466   }
467
468   if( 0u != paragraphsToBeUpdated.Count() )
469   {
470     const ParagraphRunIndex firstParagraphIndex = *( paragraphsToBeUpdated.Begin() );
471     const ParagraphRun& firstParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex );
472     mTextUpdateInfo.mParagraphCharacterIndex = firstParagraph.characterRun.characterIndex;
473
474     ParagraphRunIndex lastParagraphIndex = *( paragraphsToBeUpdated.End() - 1u );
475     const ParagraphRun& lastParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex );
476
477     if( ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) &&                                            // Some character are removed.
478         ( lastParagraphIndex < numberOfParagraphs - 1u ) &&                                                // There is a next paragraph.
479         ( ( lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters ) == // The last removed character is the new paragraph character.
480           ( mTextUpdateInfo.mCharacterIndex + mTextUpdateInfo.mNumberOfCharactersToRemove ) ) )
481     {
482       // The new paragraph character of the last updated paragraph has been removed so is going to be merged with the next one.
483       const ParagraphRun& lastParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex + 1u );
484
485       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
486     }
487     else
488     {
489       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
490     }
491   }
492
493   mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
494   mTextUpdateInfo.mStartGlyphIndex = *( mModel->mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex );
495 }
496
497 void Controller::Impl::ClearFullModelData( OperationsMask operations )
498 {
499   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
500   {
501     mModel->mLogicalModel->mLineBreakInfo.Clear();
502     mModel->mLogicalModel->mParagraphInfo.Clear();
503   }
504
505   if( NO_OPERATION != ( GET_WORD_BREAKS & operations ) )
506   {
507     mModel->mLogicalModel->mLineBreakInfo.Clear();
508   }
509
510   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
511   {
512     mModel->mLogicalModel->mScriptRuns.Clear();
513   }
514
515   if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
516   {
517     mModel->mLogicalModel->mFontRuns.Clear();
518   }
519
520   if( 0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count() )
521   {
522     if( NO_OPERATION != ( BIDI_INFO & operations ) )
523     {
524       mModel->mLogicalModel->mBidirectionalParagraphInfo.Clear();
525       mModel->mLogicalModel->mCharacterDirections.Clear();
526     }
527
528     if( NO_OPERATION != ( REORDER & operations ) )
529     {
530       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
531       for( Vector<BidirectionalLineInfoRun>::Iterator it = mModel->mLogicalModel->mBidirectionalLineInfo.Begin(),
532              endIt = mModel->mLogicalModel->mBidirectionalLineInfo.End();
533            it != endIt;
534            ++it )
535       {
536         BidirectionalLineInfoRun& bidiLineInfo = *it;
537
538         free( bidiLineInfo.visualToLogicalMap );
539         bidiLineInfo.visualToLogicalMap = NULL;
540       }
541       mModel->mLogicalModel->mBidirectionalLineInfo.Clear();
542     }
543   }
544
545   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
546   {
547     mModel->mVisualModel->mGlyphs.Clear();
548     mModel->mVisualModel->mGlyphsToCharacters.Clear();
549     mModel->mVisualModel->mCharactersToGlyph.Clear();
550     mModel->mVisualModel->mCharactersPerGlyph.Clear();
551     mModel->mVisualModel->mGlyphsPerCharacter.Clear();
552     mModel->mVisualModel->mGlyphPositions.Clear();
553   }
554
555   if( NO_OPERATION != ( LAYOUT & operations ) )
556   {
557     mModel->mVisualModel->mLines.Clear();
558   }
559
560   if( NO_OPERATION != ( COLOR & operations ) )
561   {
562     mModel->mVisualModel->mColorIndices.Clear();
563   }
564 }
565
566 void Controller::Impl::ClearCharacterModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
567 {
568   const CharacterIndex endIndexPlusOne = endIndex + 1u;
569
570   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
571   {
572     // Clear the line break info.
573     LineBreakInfo* lineBreakInfoBuffer = mModel->mLogicalModel->mLineBreakInfo.Begin();
574
575     mModel->mLogicalModel->mLineBreakInfo.Erase( lineBreakInfoBuffer + startIndex,
576                                                  lineBreakInfoBuffer + endIndexPlusOne );
577
578     // Clear the paragraphs.
579     ClearCharacterRuns( startIndex,
580                         endIndex,
581                         mModel->mLogicalModel->mParagraphInfo );
582   }
583
584   if( NO_OPERATION != ( GET_WORD_BREAKS & operations ) )
585   {
586     // Clear the word break info.
587     WordBreakInfo* wordBreakInfoBuffer = mModel->mLogicalModel->mWordBreakInfo.Begin();
588
589     mModel->mLogicalModel->mWordBreakInfo.Erase( wordBreakInfoBuffer + startIndex,
590                                          wordBreakInfoBuffer + endIndexPlusOne );
591   }
592
593   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
594   {
595     // Clear the scripts.
596     ClearCharacterRuns( startIndex,
597                         endIndex,
598                         mModel->mLogicalModel->mScriptRuns );
599   }
600
601   if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
602   {
603     // Clear the fonts.
604     ClearCharacterRuns( startIndex,
605                         endIndex,
606                         mModel->mLogicalModel->mFontRuns );
607   }
608
609   if( 0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count() )
610   {
611     if( NO_OPERATION != ( BIDI_INFO & operations ) )
612     {
613       // Clear the bidirectional paragraph info.
614       ClearCharacterRuns( startIndex,
615                           endIndex,
616                           mModel->mLogicalModel->mBidirectionalParagraphInfo );
617
618       // Clear the character's directions.
619       CharacterDirection* characterDirectionsBuffer = mModel->mLogicalModel->mCharacterDirections.Begin();
620
621       mModel->mLogicalModel->mCharacterDirections.Erase( characterDirectionsBuffer + startIndex,
622                                                          characterDirectionsBuffer + endIndexPlusOne );
623     }
624
625     if( NO_OPERATION != ( REORDER & operations ) )
626     {
627       uint32_t startRemoveIndex = mModel->mLogicalModel->mBidirectionalLineInfo.Count();
628       uint32_t endRemoveIndex = startRemoveIndex;
629       ClearCharacterRuns( startIndex,
630                           endIndex,
631                           mModel->mLogicalModel->mBidirectionalLineInfo,
632                           startRemoveIndex,
633                           endRemoveIndex );
634
635       BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mModel->mLogicalModel->mBidirectionalLineInfo.Begin();
636
637       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
638       for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfoBuffer + startRemoveIndex,
639              endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
640            it != endIt;
641            ++it )
642       {
643         BidirectionalLineInfoRun& bidiLineInfo = *it;
644
645         free( bidiLineInfo.visualToLogicalMap );
646         bidiLineInfo.visualToLogicalMap = NULL;
647       }
648
649       mModel->mLogicalModel->mBidirectionalLineInfo.Erase( bidirectionalLineInfoBuffer + startRemoveIndex,
650                                                            bidirectionalLineInfoBuffer + endRemoveIndex );
651     }
652   }
653 }
654
655 void Controller::Impl::ClearGlyphModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
656 {
657   const CharacterIndex endIndexPlusOne = endIndex + 1u;
658   const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex;
659
660   // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
661   GlyphIndex* charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
662   Length* glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
663
664   const GlyphIndex endGlyphIndexPlusOne = *( charactersToGlyphBuffer + endIndex ) + *( glyphsPerCharacterBuffer + endIndex );
665   const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
666
667   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
668   {
669     // Update the character to glyph indices.
670     for( Vector<GlyphIndex>::Iterator it =  charactersToGlyphBuffer + endIndexPlusOne,
671            endIt =  charactersToGlyphBuffer + mModel->mVisualModel->mCharactersToGlyph.Count();
672          it != endIt;
673          ++it )
674     {
675       CharacterIndex& index = *it;
676       index -= numberOfGlyphsRemoved;
677     }
678
679     // Clear the character to glyph conversion table.
680     mModel->mVisualModel->mCharactersToGlyph.Erase( charactersToGlyphBuffer + startIndex,
681                                                     charactersToGlyphBuffer + endIndexPlusOne );
682
683     // Clear the glyphs per character table.
684     mModel->mVisualModel->mGlyphsPerCharacter.Erase( glyphsPerCharacterBuffer + startIndex,
685                                                      glyphsPerCharacterBuffer + endIndexPlusOne );
686
687     // Clear the glyphs buffer.
688     GlyphInfo* glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
689     mModel->mVisualModel->mGlyphs.Erase( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
690                                          glyphsBuffer + endGlyphIndexPlusOne );
691
692     CharacterIndex* glyphsToCharactersBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
693
694     // Update the glyph to character indices.
695     for( Vector<CharacterIndex>::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
696            endIt = glyphsToCharactersBuffer + mModel->mVisualModel->mGlyphsToCharacters.Count();
697          it != endIt;
698          ++it )
699     {
700       CharacterIndex& index = *it;
701       index -= numberOfCharactersRemoved;
702     }
703
704     // Clear the glyphs to characters buffer.
705     mModel->mVisualModel->mGlyphsToCharacters.Erase( glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
706                                                      glyphsToCharactersBuffer  + endGlyphIndexPlusOne );
707
708     // Clear the characters per glyph buffer.
709     Length* charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
710     mModel->mVisualModel->mCharactersPerGlyph.Erase( charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
711                                                      charactersPerGlyphBuffer + endGlyphIndexPlusOne );
712
713     // Clear the positions buffer.
714     Vector2* positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
715     mModel->mVisualModel->mGlyphPositions.Erase( positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
716                                                  positionsBuffer + endGlyphIndexPlusOne );
717   }
718
719   if( NO_OPERATION != ( LAYOUT & operations ) )
720   {
721     // Clear the lines.
722     uint32_t startRemoveIndex = mModel->mVisualModel->mLines.Count();
723     uint32_t endRemoveIndex = startRemoveIndex;
724     ClearCharacterRuns( startIndex,
725                         endIndex,
726                         mModel->mVisualModel->mLines,
727                         startRemoveIndex,
728                         endRemoveIndex );
729
730     // Will update the glyph runs.
731     startRemoveIndex = mModel->mVisualModel->mLines.Count();
732     endRemoveIndex = startRemoveIndex;
733     ClearGlyphRuns( mTextUpdateInfo.mStartGlyphIndex,
734                     endGlyphIndexPlusOne - 1u,
735                     mModel->mVisualModel->mLines,
736                     startRemoveIndex,
737                     endRemoveIndex );
738
739     // Set the line index from where to insert the new laid-out lines.
740     mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
741
742     LineRun* linesBuffer = mModel->mVisualModel->mLines.Begin();
743     mModel->mVisualModel->mLines.Erase( linesBuffer + startRemoveIndex,
744                                         linesBuffer + endRemoveIndex );
745   }
746
747   if( NO_OPERATION != ( COLOR & operations ) )
748   {
749     if( 0u != mModel->mVisualModel->mColorIndices.Count() )
750     {
751       ColorIndex* colorIndexBuffer = mModel->mVisualModel->mColorIndices.Begin();
752       mModel->mVisualModel->mColorIndices.Erase( colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
753                                                  colorIndexBuffer + endGlyphIndexPlusOne );
754     }
755   }
756 }
757
758 void Controller::Impl::ClearModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
759 {
760   if( mTextUpdateInfo.mClearAll ||
761       ( ( 0u == startIndex ) &&
762         ( mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u ) ) )
763   {
764     ClearFullModelData( operations );
765   }
766   else
767   {
768     // Clear the model data related with characters.
769     ClearCharacterModelData( startIndex, endIndex, operations );
770
771     // Clear the model data related with glyphs.
772     ClearGlyphModelData( startIndex, endIndex, operations );
773   }
774
775   // The estimated number of lines. Used to avoid reallocations when layouting.
776   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
777
778   mModel->mVisualModel->ClearCaches();
779 }
780
781 bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
782 {
783   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel\n" );
784
785   // Calculate the operations to be done.
786   const OperationsMask operations = static_cast<OperationsMask>( mOperationsPending & operationsRequired );
787
788   if( NO_OPERATION == operations )
789   {
790     // Nothing to do if no operations are pending and required.
791     return false;
792   }
793
794   Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
795   Vector<Character> displayCharacters;
796   bool useHiddenText = false;
797   if ( mHiddenInput && mEventData != NULL && !mEventData->mIsShowingPlaceholderText)
798   {
799     mHiddenInput->Substitute( srcCharacters,displayCharacters );
800     useHiddenText = true;
801   }
802
803   Vector<Character>& utf32Characters = useHiddenText ? displayCharacters : srcCharacters;
804   const Length numberOfCharacters = utf32Characters.Count();
805
806   // Index to the first character of the first paragraph to be updated.
807   CharacterIndex startIndex = 0u;
808   // Number of characters of the paragraphs to be removed.
809   Length paragraphCharacters = 0u;
810
811   CalculateTextUpdateIndices( paragraphCharacters );
812   startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
813
814   if( mTextUpdateInfo.mClearAll ||
815       ( 0u != paragraphCharacters ) )
816   {
817     ClearModelData( startIndex, startIndex + ( ( paragraphCharacters > 0u ) ? paragraphCharacters - 1u : 0u ), operations );
818   }
819
820   mTextUpdateInfo.mClearAll = false;
821
822   // Whether the model is updated.
823   bool updated = false;
824
825   Vector<LineBreakInfo>& lineBreakInfo = mModel->mLogicalModel->mLineBreakInfo;
826   const Length requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
827
828   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
829   {
830     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
831     // calculate the bidirectional info for each 'paragraph'.
832     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
833     // is not shaped together).
834     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
835
836     SetLineBreakInfo( utf32Characters,
837                       startIndex,
838                       requestedNumberOfCharacters,
839                       lineBreakInfo );
840
841     // Create the paragraph info.
842     mModel->mLogicalModel->CreateParagraphInfo( startIndex,
843                                                 requestedNumberOfCharacters );
844     updated = true;
845   }
846
847   Vector<WordBreakInfo>& wordBreakInfo = mModel->mLogicalModel->mWordBreakInfo;
848   if( NO_OPERATION != ( GET_WORD_BREAKS & operations ) )
849   {
850     // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
851     wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
852
853     SetWordBreakInfo( utf32Characters,
854                       startIndex,
855                       requestedNumberOfCharacters,
856                       wordBreakInfo );
857     updated = true;
858   }
859
860   const bool getScripts = NO_OPERATION != ( GET_SCRIPTS & operations );
861   const bool validateFonts = NO_OPERATION != ( VALIDATE_FONTS & operations );
862
863   Vector<ScriptRun>& scripts = mModel->mLogicalModel->mScriptRuns;
864   Vector<FontRun>& validFonts = mModel->mLogicalModel->mFontRuns;
865
866   if( getScripts || validateFonts )
867   {
868     // Validates the fonts assigned by the application or assigns default ones.
869     // It makes sure all the characters are going to be rendered by the correct font.
870     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
871
872     if( getScripts )
873     {
874       // Retrieves the scripts used in the text.
875       multilanguageSupport.SetScripts( utf32Characters,
876                                        startIndex,
877                                        requestedNumberOfCharacters,
878                                        scripts );
879     }
880
881     if( validateFonts )
882     {
883       // Validate the fonts set through the mark-up string.
884       Vector<FontDescriptionRun>& fontDescriptionRuns = mModel->mLogicalModel->mFontDescriptionRuns;
885
886       // Get the default font's description.
887       TextAbstraction::FontDescription defaultFontDescription;
888       TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
889
890       if( IsShowingPlaceholderText() && ( NULL != mEventData->mPlaceholderFont ) )
891       {
892         // If the placeholder font is set specifically, only placeholder font is changed.
893         defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
894         if( mEventData->mPlaceholderFont->sizeDefined )
895         {
896           defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * 64u;
897         }
898       }
899       else if( NULL != mFontDefaults )
900       {
901         // Set the normal font and the placeholder font.
902         defaultFontDescription = mFontDefaults->mFontDescription;
903         defaultPointSize = mFontDefaults->mDefaultPointSize * 64u;
904       }
905
906       // Validates the fonts. If there is a character with no assigned font it sets a default one.
907       // After this call, fonts are validated.
908       multilanguageSupport.ValidateFonts( utf32Characters,
909                                           scripts,
910                                           fontDescriptionRuns,
911                                           defaultFontDescription,
912                                           defaultPointSize,
913                                           startIndex,
914                                           requestedNumberOfCharacters,
915                                           validFonts );
916     }
917     updated = true;
918   }
919
920   Vector<Character> mirroredUtf32Characters;
921   bool textMirrored = false;
922   const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
923   if( NO_OPERATION != ( BIDI_INFO & operations ) )
924   {
925     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mModel->mLogicalModel->mBidirectionalParagraphInfo;
926     bidirectionalInfo.Reserve( numberOfParagraphs );
927
928     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
929     SetBidirectionalInfo( utf32Characters,
930                           scripts,
931                           lineBreakInfo,
932                           startIndex,
933                           requestedNumberOfCharacters,
934                           bidirectionalInfo );
935
936     if( 0u != bidirectionalInfo.Count() )
937     {
938       // Only set the character directions if there is right to left characters.
939       Vector<CharacterDirection>& directions = mModel->mLogicalModel->mCharacterDirections;
940       GetCharactersDirection( bidirectionalInfo,
941                               numberOfCharacters,
942                               startIndex,
943                               requestedNumberOfCharacters,
944                               directions );
945
946       // This paragraph has right to left text. Some characters may need to be mirrored.
947       // TODO: consider if the mirrored string can be stored as well.
948
949       textMirrored = GetMirroredText( utf32Characters,
950                                       directions,
951                                       bidirectionalInfo,
952                                       startIndex,
953                                       requestedNumberOfCharacters,
954                                       mirroredUtf32Characters );
955     }
956     else
957     {
958       // There is no right to left characters. Clear the directions vector.
959       mModel->mLogicalModel->mCharacterDirections.Clear();
960     }
961     updated = true;
962   }
963
964   Vector<GlyphInfo>& glyphs = mModel->mVisualModel->mGlyphs;
965   Vector<CharacterIndex>& glyphsToCharactersMap = mModel->mVisualModel->mGlyphsToCharacters;
966   Vector<Length>& charactersPerGlyph = mModel->mVisualModel->mCharactersPerGlyph;
967   Vector<GlyphIndex> newParagraphGlyphs;
968   newParagraphGlyphs.Reserve( numberOfParagraphs );
969
970   const Length currentNumberOfGlyphs = glyphs.Count();
971   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
972   {
973     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
974     // Shapes the text.
975     ShapeText( textToShape,
976                lineBreakInfo,
977                scripts,
978                validFonts,
979                startIndex,
980                mTextUpdateInfo.mStartGlyphIndex,
981                requestedNumberOfCharacters,
982                glyphs,
983                glyphsToCharactersMap,
984                charactersPerGlyph,
985                newParagraphGlyphs );
986
987     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
988     mModel->mVisualModel->CreateGlyphsPerCharacterTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
989     mModel->mVisualModel->CreateCharacterToGlyphTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
990     updated = true;
991   }
992
993   const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
994
995   if( NO_OPERATION != ( GET_GLYPH_METRICS & operations ) )
996   {
997     GlyphInfo* glyphsBuffer = glyphs.Begin();
998     mMetrics->GetGlyphMetrics( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs );
999
1000     // Update the width and advance of all new paragraph characters.
1001     for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it )
1002     {
1003       const GlyphIndex index = *it;
1004       GlyphInfo& glyph = *( glyphsBuffer + index );
1005
1006       glyph.xBearing = 0.f;
1007       glyph.width = 0.f;
1008       glyph.advance = 0.f;
1009     }
1010     updated = true;
1011   }
1012
1013   if( NO_OPERATION != ( COLOR & operations ) )
1014   {
1015     // Set the color runs in glyphs.
1016     SetColorSegmentationInfo( mModel->mLogicalModel->mColorRuns,
1017                               mModel->mVisualModel->mCharactersToGlyph,
1018                               mModel->mVisualModel->mGlyphsPerCharacter,
1019                               startIndex,
1020                               mTextUpdateInfo.mStartGlyphIndex,
1021                               requestedNumberOfCharacters,
1022                               mModel->mVisualModel->mColors,
1023                               mModel->mVisualModel->mColorIndices );
1024
1025     updated = true;
1026   }
1027
1028   if( ( NULL != mEventData ) &&
1029       mEventData->mPreEditFlag &&
1030       ( 0u != mModel->mVisualModel->mCharactersToGlyph.Count() ) )
1031   {
1032     // Add the underline for the pre-edit text.
1033     const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
1034     const Length* const glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
1035
1036     const GlyphIndex glyphStart = *( charactersToGlyphBuffer + mEventData->mPreEditStartPosition );
1037     const CharacterIndex lastPreEditCharacter = mEventData->mPreEditStartPosition + ( ( mEventData->mPreEditLength > 0u ) ? mEventData->mPreEditLength - 1u : 0u );
1038     const Length numberOfGlyphsLastCharacter = *( glyphsPerCharacterBuffer + lastPreEditCharacter );
1039     const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + lastPreEditCharacter ) + ( numberOfGlyphsLastCharacter > 1u ? numberOfGlyphsLastCharacter - 1u : 0u );
1040
1041     GlyphRun underlineRun;
1042     underlineRun.glyphIndex = glyphStart;
1043     underlineRun.numberOfGlyphs = 1u + glyphEnd - glyphStart;
1044
1045     // TODO: At the moment the underline runs are only for pre-edit.
1046     mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1047   }
1048
1049   // The estimated number of lines. Used to avoid reallocations when layouting.
1050   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
1051
1052   // Set the previous number of characters for the next time the text is updated.
1053   mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
1054
1055   return updated;
1056 }
1057
1058 void Controller::Impl::RetrieveDefaultInputStyle( InputStyle& inputStyle )
1059 {
1060   // Sets the default text's color.
1061   inputStyle.textColor = mTextColor;
1062   inputStyle.isDefaultColor = true;
1063
1064   inputStyle.familyName.clear();
1065   inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
1066   inputStyle.width = TextAbstraction::FontWidth::NORMAL;
1067   inputStyle.slant = TextAbstraction::FontSlant::NORMAL;
1068   inputStyle.size = 0.f;
1069
1070   inputStyle.lineSpacing = 0.f;
1071
1072   inputStyle.underlineProperties.clear();
1073   inputStyle.shadowProperties.clear();
1074   inputStyle.embossProperties.clear();
1075   inputStyle.outlineProperties.clear();
1076
1077   inputStyle.isFamilyDefined = false;
1078   inputStyle.isWeightDefined = false;
1079   inputStyle.isWidthDefined = false;
1080   inputStyle.isSlantDefined = false;
1081   inputStyle.isSizeDefined = false;
1082
1083   inputStyle.isLineSpacingDefined = false;
1084
1085   inputStyle.isUnderlineDefined = false;
1086   inputStyle.isShadowDefined = false;
1087   inputStyle.isEmbossDefined = false;
1088   inputStyle.isOutlineDefined = false;
1089
1090   // Sets the default font's family name, weight, width, slant and size.
1091   if( mFontDefaults )
1092   {
1093     if( mFontDefaults->familyDefined )
1094     {
1095       inputStyle.familyName = mFontDefaults->mFontDescription.family;
1096       inputStyle.isFamilyDefined = true;
1097     }
1098
1099     if( mFontDefaults->weightDefined )
1100     {
1101       inputStyle.weight = mFontDefaults->mFontDescription.weight;
1102       inputStyle.isWeightDefined = true;
1103     }
1104
1105     if( mFontDefaults->widthDefined )
1106     {
1107       inputStyle.width = mFontDefaults->mFontDescription.width;
1108       inputStyle.isWidthDefined = true;
1109     }
1110
1111     if( mFontDefaults->slantDefined )
1112     {
1113       inputStyle.slant = mFontDefaults->mFontDescription.slant;
1114       inputStyle.isSlantDefined = true;
1115     }
1116
1117     if( mFontDefaults->sizeDefined )
1118     {
1119       inputStyle.size = mFontDefaults->mDefaultPointSize;
1120       inputStyle.isSizeDefined = true;
1121     }
1122   }
1123 }
1124
1125 float Controller::Impl::GetDefaultFontLineHeight()
1126 {
1127   FontId defaultFontId = 0u;
1128   if( NULL == mFontDefaults )
1129   {
1130     TextAbstraction::FontDescription fontDescription;
1131     defaultFontId = mFontClient.GetFontId( fontDescription );
1132   }
1133   else
1134   {
1135     defaultFontId = mFontDefaults->GetFontId( mFontClient );
1136   }
1137
1138   Text::FontMetrics fontMetrics;
1139   mMetrics->GetFontMetrics( defaultFontId, fontMetrics );
1140
1141   return( fontMetrics.ascender - fontMetrics.descender );
1142 }
1143
1144 void Controller::Impl::OnCursorKeyEvent( const Event& event )
1145 {
1146   if( NULL == mEventData )
1147   {
1148     // Nothing to do if there is no text input.
1149     return;
1150   }
1151
1152   int keyCode = event.p1.mInt;
1153
1154   if( Dali::DALI_KEY_CURSOR_LEFT == keyCode )
1155   {
1156     if( mEventData->mPrimaryCursorPosition > 0u )
1157     {
1158       mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition - 1u );
1159     }
1160   }
1161   else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
1162   {
1163     if( mModel->mLogicalModel->mText.Count() > mEventData->mPrimaryCursorPosition )
1164     {
1165       mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
1166     }
1167   }
1168   else if( Dali::DALI_KEY_CURSOR_UP == keyCode )
1169   {
1170     // Get first the line index of the current cursor position index.
1171     CharacterIndex characterIndex = 0u;
1172
1173     if( mEventData->mPrimaryCursorPosition > 0u )
1174     {
1175       characterIndex = mEventData->mPrimaryCursorPosition - 1u;
1176     }
1177
1178     const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( characterIndex );
1179     const LineIndex previousLineIndex = ( lineIndex > 0 ? lineIndex - 1u : lineIndex );
1180
1181     // Retrieve the cursor position info.
1182     CursorInfo cursorInfo;
1183     GetCursorPosition( mEventData->mPrimaryCursorPosition,
1184                        cursorInfo );
1185
1186     // Get the line above.
1187     const LineRun& line = *( mModel->mVisualModel->mLines.Begin() + previousLineIndex );
1188
1189     // Get the next hit 'y' point.
1190     const float hitPointY = cursorInfo.lineOffset - 0.5f * ( line.ascender - line.descender );
1191
1192     // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
1193     bool matchedCharacter = false;
1194     mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1195                                                                       mModel->mLogicalModel,
1196                                                                       mMetrics,
1197                                                                       mEventData->mCursorHookPositionX,
1198                                                                       hitPointY,
1199                                                                       CharacterHitTest::TAP,
1200                                                                       matchedCharacter );
1201   }
1202   else if( Dali::DALI_KEY_CURSOR_DOWN == keyCode )
1203   {
1204     // Get first the line index of the current cursor position index.
1205     CharacterIndex characterIndex = 0u;
1206
1207     if( mEventData->mPrimaryCursorPosition > 0u )
1208     {
1209       characterIndex = mEventData->mPrimaryCursorPosition - 1u;
1210     }
1211
1212     const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( characterIndex );
1213
1214     if( lineIndex + 1u < mModel->mVisualModel->mLines.Count() )
1215     {
1216       // Retrieve the cursor position info.
1217       CursorInfo cursorInfo;
1218       GetCursorPosition( mEventData->mPrimaryCursorPosition,
1219                          cursorInfo );
1220
1221       // Get the line below.
1222       const LineRun& line = *( mModel->mVisualModel->mLines.Begin() + lineIndex + 1u );
1223
1224       // Get the next hit 'y' point.
1225       const float hitPointY = cursorInfo.lineOffset + cursorInfo.lineHeight + 0.5f * ( line.ascender - line.descender );
1226
1227       // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
1228       bool matchedCharacter = false;
1229       mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1230                                                                         mModel->mLogicalModel,
1231                                                                         mMetrics,
1232                                                                         mEventData->mCursorHookPositionX,
1233                                                                         hitPointY,
1234                                                                         CharacterHitTest::TAP,
1235                                                                         matchedCharacter );
1236     }
1237   }
1238
1239   mEventData->mUpdateCursorPosition = true;
1240   mEventData->mUpdateInputStyle = true;
1241   mEventData->mScrollAfterUpdatePosition = true;
1242 }
1243
1244 void Controller::Impl::OnTapEvent( const Event& event )
1245 {
1246   if( NULL != mEventData )
1247   {
1248     const unsigned int tapCount = event.p1.mUint;
1249
1250     if( 1u == tapCount )
1251     {
1252       if( IsShowingRealText() )
1253       {
1254         // Convert from control's coords to text's coords.
1255         const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1256         const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1257
1258         // Keep the tap 'x' position. Used to move the cursor.
1259         mEventData->mCursorHookPositionX = xPosition;
1260
1261         // Whether to touch point hits on a glyph.
1262         bool matchedCharacter = false;
1263         mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1264                                                                           mModel->mLogicalModel,
1265                                                                           mMetrics,
1266                                                                           xPosition,
1267                                                                           yPosition,
1268                                                                           CharacterHitTest::TAP,
1269                                                                           matchedCharacter );
1270
1271         // When the cursor position is changing, delay cursor blinking
1272         mEventData->mDecorator->DelayCursorBlink();
1273       }
1274       else
1275       {
1276         mEventData->mPrimaryCursorPosition = 0u;
1277       }
1278
1279       mEventData->mUpdateCursorPosition = true;
1280       mEventData->mUpdateGrabHandlePosition = true;
1281       mEventData->mScrollAfterUpdatePosition = true;
1282       mEventData->mUpdateInputStyle = true;
1283
1284       // Notify the cursor position to the imf manager.
1285       if( mEventData->mImfManager )
1286       {
1287         mEventData->mImfManager.SetCursorPosition( mEventData->mPrimaryCursorPosition );
1288         mEventData->mImfManager.NotifyCursorPosition();
1289       }
1290     }
1291     else if( 2u == tapCount )
1292     {
1293       if( mEventData->mSelectionEnabled )
1294       {
1295         // Convert from control's coords to text's coords.
1296         const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1297         const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1298
1299         // Calculates the logical position from the x,y coords.
1300         RepositionSelectionHandles( xPosition,
1301                                     yPosition,
1302                                     mEventData->mDoubleTapAction );
1303       }
1304     }
1305   }
1306 }
1307
1308 void Controller::Impl::OnPanEvent( const Event& event )
1309 {
1310   if( NULL == mEventData )
1311   {
1312     // Nothing to do if there is no text input.
1313     return;
1314   }
1315
1316   const bool isHorizontalScrollEnabled = mEventData->mDecorator->IsHorizontalScrollEnabled();
1317   const bool isVerticalScrollEnabled = mEventData->mDecorator->IsVerticalScrollEnabled();
1318
1319   if( !isHorizontalScrollEnabled && !isVerticalScrollEnabled )
1320   {
1321     // Nothing to do if scrolling is not enabled.
1322     return;
1323   }
1324
1325   const int state = event.p1.mInt;
1326
1327   switch( state )
1328   {
1329     case Gesture::Started:
1330     {
1331       // Will remove the cursor, handles or text's popup, ...
1332       ChangeState( EventData::TEXT_PANNING );
1333       break;
1334     }
1335     case Gesture::Continuing:
1336     {
1337       const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
1338       const Vector2 currentScroll = mModel->mScrollPosition;
1339
1340       if( isHorizontalScrollEnabled )
1341       {
1342         const float displacementX = event.p2.mFloat;
1343         mModel->mScrollPosition.x += displacementX;
1344
1345         ClampHorizontalScroll( layoutSize );
1346       }
1347
1348       if( isVerticalScrollEnabled )
1349       {
1350         const float displacementY = event.p3.mFloat;
1351         mModel->mScrollPosition.y += displacementY;
1352
1353         ClampVerticalScroll( layoutSize );
1354       }
1355
1356       mEventData->mDecorator->UpdatePositions( mModel->mScrollPosition - currentScroll );
1357       break;
1358     }
1359     case Gesture::Finished:
1360     case Gesture::Cancelled: // FALLTHROUGH
1361     {
1362       // Will go back to the previous state to show the cursor, handles, the text's popup, ...
1363       ChangeState( mEventData->mPreviousState );
1364       break;
1365     }
1366     default:
1367       break;
1368   }
1369 }
1370
1371 void Controller::Impl::OnLongPressEvent( const Event& event )
1372 {
1373   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::OnLongPressEvent\n" );
1374
1375   if( !IsShowingRealText() && ( EventData::EDITING == mEventData->mState ) )
1376   {
1377     ChangeState( EventData::EDITING_WITH_POPUP );
1378     mEventData->mDecoratorUpdated = true;
1379     mEventData->mUpdateInputStyle = true;
1380   }
1381   else
1382   {
1383     if( mEventData->mSelectionEnabled )
1384     {
1385       // Convert from control's coords to text's coords.
1386       const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1387       const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1388
1389       // Calculates the logical position from the x,y coords.
1390       RepositionSelectionHandles( xPosition,
1391                                   yPosition,
1392                                   mEventData->mLongPressAction );
1393     }
1394   }
1395 }
1396
1397 void Controller::Impl::OnHandleEvent( const Event& event )
1398 {
1399   if( NULL == mEventData )
1400   {
1401     // Nothing to do if there is no text input.
1402     return;
1403   }
1404
1405   const unsigned int state = event.p1.mUint;
1406   const bool handleStopScrolling = ( HANDLE_STOP_SCROLLING == state );
1407   const bool isSmoothHandlePanEnabled = mEventData->mDecorator->IsSmoothHandlePanEnabled();
1408
1409   if( HANDLE_PRESSED == state )
1410   {
1411     // Convert from decorator's coords to text's coords.
1412     const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1413     const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1414
1415     // Need to calculate the handle's new position.
1416     bool matchedCharacter = false;
1417     const CharacterIndex handleNewPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1418                                                                           mModel->mLogicalModel,
1419                                                                           mMetrics,
1420                                                                           xPosition,
1421                                                                           yPosition,
1422                                                                           CharacterHitTest::SCROLL,
1423                                                                           matchedCharacter );
1424
1425     if( Event::GRAB_HANDLE_EVENT == event.type )
1426     {
1427       ChangeState ( EventData::GRAB_HANDLE_PANNING );
1428
1429       if( handleNewPosition != mEventData->mPrimaryCursorPosition )
1430       {
1431         // Updates the cursor position if the handle's new position is different than the current one.
1432         mEventData->mUpdateCursorPosition = true;
1433         // Does not update the grab handle position if the smooth panning is enabled. (The decorator does it smooth).
1434         mEventData->mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
1435         mEventData->mPrimaryCursorPosition = handleNewPosition;
1436       }
1437
1438       // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
1439       mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
1440     }
1441     else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
1442     {
1443       ChangeState ( EventData::SELECTION_HANDLE_PANNING );
1444
1445       if( ( handleNewPosition != mEventData->mLeftSelectionPosition ) &&
1446           ( handleNewPosition != mEventData->mRightSelectionPosition ) )
1447       {
1448         // Updates the highlight box if the handle's new position is different than the current one.
1449         mEventData->mUpdateHighlightBox = true;
1450         // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
1451         mEventData->mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
1452         mEventData->mLeftSelectionPosition = handleNewPosition;
1453       }
1454
1455       // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
1456       mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
1457
1458       // Will define the order to scroll the text to match the handle position.
1459       mEventData->mIsLeftHandleSelected = true;
1460       mEventData->mIsRightHandleSelected = false;
1461     }
1462     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
1463     {
1464       ChangeState ( EventData::SELECTION_HANDLE_PANNING );
1465
1466       if( ( handleNewPosition != mEventData->mRightSelectionPosition ) &&
1467           ( handleNewPosition != mEventData->mLeftSelectionPosition ) )
1468       {
1469         // Updates the highlight box if the handle's new position is different than the current one.
1470         mEventData->mUpdateHighlightBox = true;
1471         // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
1472         mEventData->mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
1473         mEventData->mRightSelectionPosition = handleNewPosition;
1474       }
1475
1476       // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
1477       mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
1478
1479       // Will define the order to scroll the text to match the handle position.
1480       mEventData->mIsLeftHandleSelected = false;
1481       mEventData->mIsRightHandleSelected = true;
1482     }
1483   } // end ( HANDLE_PRESSED == state )
1484   else if( ( HANDLE_RELEASED == state ) ||
1485            handleStopScrolling )
1486   {
1487     CharacterIndex handlePosition = 0u;
1488     if( handleStopScrolling || isSmoothHandlePanEnabled )
1489     {
1490       // Convert from decorator's coords to text's coords.
1491       const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1492       const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1493
1494       bool matchedCharacter = false;
1495       handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1496                                                     mModel->mLogicalModel,
1497                                                     mMetrics,
1498                                                     xPosition,
1499                                                     yPosition,
1500                                                     CharacterHitTest::SCROLL,
1501                                                     matchedCharacter );
1502     }
1503
1504     if( Event::GRAB_HANDLE_EVENT == event.type )
1505     {
1506       mEventData->mUpdateCursorPosition = true;
1507       mEventData->mUpdateGrabHandlePosition = true;
1508       mEventData->mUpdateInputStyle = true;
1509
1510       if( !IsClipboardEmpty() )
1511       {
1512         ChangeState( EventData::EDITING_WITH_PASTE_POPUP ); // Moving grabhandle will show Paste Popup
1513       }
1514
1515       if( handleStopScrolling || isSmoothHandlePanEnabled )
1516       {
1517         mEventData->mScrollAfterUpdatePosition = true;
1518         mEventData->mPrimaryCursorPosition = handlePosition;
1519       }
1520     }
1521     else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
1522     {
1523       ChangeState( EventData::SELECTING );
1524
1525       mEventData->mUpdateHighlightBox = true;
1526       mEventData->mUpdateLeftSelectionPosition = true;
1527       mEventData->mUpdateRightSelectionPosition = true;
1528
1529       if( handleStopScrolling || isSmoothHandlePanEnabled )
1530       {
1531         mEventData->mScrollAfterUpdatePosition = true;
1532
1533         if( ( handlePosition != mEventData->mRightSelectionPosition ) &&
1534             ( handlePosition != mEventData->mLeftSelectionPosition ) )
1535         {
1536           mEventData->mLeftSelectionPosition = handlePosition;
1537         }
1538       }
1539     }
1540     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
1541     {
1542       ChangeState( EventData::SELECTING );
1543
1544       mEventData->mUpdateHighlightBox = true;
1545       mEventData->mUpdateRightSelectionPosition = true;
1546       mEventData->mUpdateLeftSelectionPosition = true;
1547
1548       if( handleStopScrolling || isSmoothHandlePanEnabled )
1549       {
1550         mEventData->mScrollAfterUpdatePosition = true;
1551         if( ( handlePosition != mEventData->mRightSelectionPosition ) &&
1552             ( handlePosition != mEventData->mLeftSelectionPosition ) )
1553         {
1554           mEventData->mRightSelectionPosition = handlePosition;
1555         }
1556       }
1557     }
1558
1559     mEventData->mDecoratorUpdated = true;
1560   } // end ( ( HANDLE_RELEASED == state ) || ( HANDLE_STOP_SCROLLING == state ) )
1561   else if( HANDLE_SCROLLING == state )
1562   {
1563     const float xSpeed = event.p2.mFloat;
1564     const float ySpeed = event.p3.mFloat;
1565     const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
1566     const Vector2 currentScrollPosition = mModel->mScrollPosition;
1567
1568     mModel->mScrollPosition.x += xSpeed;
1569     mModel->mScrollPosition.y += ySpeed;
1570
1571     ClampHorizontalScroll( layoutSize );
1572     ClampVerticalScroll( layoutSize );
1573
1574     bool endOfScroll = false;
1575     if( Vector2::ZERO == ( currentScrollPosition - mModel->mScrollPosition ) )
1576     {
1577       // Notify the decorator there is no more text to scroll.
1578       // The decorator won't send more scroll events.
1579       mEventData->mDecorator->NotifyEndOfScroll();
1580       // Still need to set the position of the handle.
1581       endOfScroll = true;
1582     }
1583
1584     // Set the position of the handle.
1585     const bool scrollRightDirection = xSpeed > 0.f;
1586     const bool scrollBottomDirection = ySpeed > 0.f;
1587     const bool leftSelectionHandleEvent = Event::LEFT_SELECTION_HANDLE_EVENT == event.type;
1588     const bool rightSelectionHandleEvent = Event::RIGHT_SELECTION_HANDLE_EVENT == event.type;
1589
1590     if( Event::GRAB_HANDLE_EVENT == event.type )
1591     {
1592       ChangeState( EventData::GRAB_HANDLE_PANNING );
1593
1594       // Get the grab handle position in decorator coords.
1595       Vector2 position = mEventData->mDecorator->GetPosition( GRAB_HANDLE );
1596
1597       if( mEventData->mDecorator->IsHorizontalScrollEnabled() )
1598       {
1599         // Position the grag handle close to either the left or right edge.
1600         position.x = scrollRightDirection ? 0.f : mModel->mVisualModel->mControlSize.width;
1601       }
1602
1603       if( mEventData->mDecorator->IsVerticalScrollEnabled() )
1604       {
1605         position.x = mEventData->mCursorHookPositionX;
1606
1607         // Position the grag handle close to either the top or bottom edge.
1608         position.y = scrollBottomDirection ? 0.f : mModel->mVisualModel->mControlSize.height;
1609       }
1610
1611       // Get the new handle position.
1612       // The grab handle's position is in decorator's coords. Need to transforms to text's coords.
1613       bool matchedCharacter = false;
1614       const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1615                                                                          mModel->mLogicalModel,
1616                                                                          mMetrics,
1617                                                                          position.x - mModel->mScrollPosition.x,
1618                                                                          position.y - mModel->mScrollPosition.y,
1619                                                                          CharacterHitTest::SCROLL,
1620                                                                          matchedCharacter );
1621
1622       if( mEventData->mPrimaryCursorPosition != handlePosition )
1623       {
1624         mEventData->mUpdateCursorPosition = true;
1625         mEventData->mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
1626         mEventData->mScrollAfterUpdatePosition = true;
1627         mEventData->mPrimaryCursorPosition = handlePosition;
1628       }
1629       mEventData->mUpdateInputStyle = mEventData->mUpdateCursorPosition;
1630
1631       // Updates the decorator if the soft handle panning is enabled.
1632       mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
1633     }
1634     else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
1635     {
1636       ChangeState( EventData::SELECTION_HANDLE_PANNING );
1637
1638       // Get the selection handle position in decorator coords.
1639       Vector2 position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
1640
1641       if( mEventData->mDecorator->IsHorizontalScrollEnabled() )
1642       {
1643         // Position the selection handle close to either the left or right edge.
1644         position.x = scrollRightDirection ? 0.f : mModel->mVisualModel->mControlSize.width;
1645       }
1646
1647       if( mEventData->mDecorator->IsVerticalScrollEnabled() )
1648       {
1649         position.x = mEventData->mCursorHookPositionX;
1650
1651         // Position the grag handle close to either the top or bottom edge.
1652         position.y = scrollBottomDirection ? 0.f : mModel->mVisualModel->mControlSize.height;
1653       }
1654
1655       // Get the new handle position.
1656       // The selection handle's position is in decorator's coords. Need to transform to text's coords.
1657       bool matchedCharacter = false;
1658       const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1659                                                                          mModel->mLogicalModel,
1660                                                                          mMetrics,
1661                                                                          position.x - mModel->mScrollPosition.x,
1662                                                                          position.y - mModel->mScrollPosition.y,
1663                                                                          CharacterHitTest::SCROLL,
1664                                                                          matchedCharacter );
1665
1666       if( leftSelectionHandleEvent )
1667       {
1668         const bool differentHandles = ( mEventData->mLeftSelectionPosition != handlePosition ) && ( mEventData->mRightSelectionPosition != handlePosition );
1669
1670         if( differentHandles || endOfScroll )
1671         {
1672           mEventData->mUpdateHighlightBox = true;
1673           mEventData->mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
1674           mEventData->mUpdateRightSelectionPosition = isSmoothHandlePanEnabled;
1675           mEventData->mLeftSelectionPosition = handlePosition;
1676         }
1677       }
1678       else
1679       {
1680         const bool differentHandles = ( mEventData->mRightSelectionPosition != handlePosition ) && ( mEventData->mLeftSelectionPosition != handlePosition );
1681         if( differentHandles || endOfScroll )
1682         {
1683           mEventData->mUpdateHighlightBox = true;
1684           mEventData->mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
1685           mEventData->mUpdateLeftSelectionPosition = isSmoothHandlePanEnabled;
1686           mEventData->mRightSelectionPosition = handlePosition;
1687         }
1688       }
1689
1690       if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
1691       {
1692         RepositionSelectionHandles();
1693
1694         mEventData->mScrollAfterUpdatePosition = !isSmoothHandlePanEnabled;
1695       }
1696     }
1697     mEventData->mDecoratorUpdated = true;
1698   } // end ( HANDLE_SCROLLING == state )
1699 }
1700
1701 void Controller::Impl::OnSelectEvent( const Event& event )
1702 {
1703   if( NULL == mEventData )
1704   {
1705     // Nothing to do if there is no text.
1706     return;
1707   }
1708
1709   if( mEventData->mSelectionEnabled )
1710   {
1711     // Convert from control's coords to text's coords.
1712     const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1713     const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1714
1715     // Calculates the logical position from the x,y coords.
1716     RepositionSelectionHandles( xPosition,
1717                                 yPosition,
1718                                 Controller::NoTextTap::HIGHLIGHT );
1719   }
1720 }
1721
1722 void Controller::Impl::OnSelectAllEvent()
1723 {
1724   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "OnSelectAllEvent mEventData->mSelectionEnabled%s \n", mEventData->mSelectionEnabled?"true":"false");
1725
1726   if( NULL == mEventData )
1727   {
1728     // Nothing to do if there is no text.
1729     return;
1730   }
1731
1732   if( mEventData->mSelectionEnabled )
1733   {
1734     ChangeState( EventData::SELECTING );
1735
1736     mEventData->mLeftSelectionPosition = 0u;
1737     mEventData->mRightSelectionPosition = mModel->mLogicalModel->mText.Count();
1738
1739     mEventData->mScrollAfterUpdatePosition = true;
1740     mEventData->mUpdateLeftSelectionPosition = true;
1741     mEventData->mUpdateRightSelectionPosition = true;
1742     mEventData->mUpdateHighlightBox = true;
1743   }
1744 }
1745
1746 void Controller::Impl::RetrieveSelection( std::string& selectedText, bool deleteAfterRetrieval )
1747 {
1748   if( mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition )
1749   {
1750     // Nothing to select if handles are in the same place.
1751     selectedText.clear();
1752     return;
1753   }
1754
1755   const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
1756
1757   //Get start and end position of selection
1758   const CharacterIndex startOfSelectedText = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1759   const Length lengthOfSelectedText = ( handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition ) - startOfSelectedText;
1760
1761   Vector<Character>& utf32Characters = mModel->mLogicalModel->mText;
1762   const Length numberOfCharacters = utf32Characters.Count();
1763
1764   // Validate the start and end selection points
1765   if( ( startOfSelectedText + lengthOfSelectedText ) <= numberOfCharacters )
1766   {
1767     //Get text as a UTF8 string
1768     Utf32ToUtf8( &utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText );
1769
1770     if( deleteAfterRetrieval ) // Only delete text if copied successfully
1771     {
1772       // Keep a copy of the current input style.
1773       InputStyle currentInputStyle;
1774       currentInputStyle.Copy( mEventData->mInputStyle );
1775
1776       // Set as input style the style of the first deleted character.
1777       mModel->mLogicalModel->RetrieveStyle( startOfSelectedText, mEventData->mInputStyle );
1778
1779       // Compare if the input style has changed.
1780       const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle );
1781
1782       if( hasInputStyleChanged )
1783       {
1784         const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle );
1785         // Queue the input style changed signal.
1786         mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
1787       }
1788
1789       mModel->mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
1790
1791       // Mark the paragraphs to be updated.
1792       mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1793       mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1794
1795       // Delete text between handles
1796       Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
1797       Vector<Character>::Iterator last  = first + lengthOfSelectedText;
1798       utf32Characters.Erase( first, last );
1799
1800       // Will show the cursor at the first character of the selection.
1801       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1802     }
1803     else
1804     {
1805       // Will show the cursor at the last character of the selection.
1806       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
1807     }
1808
1809     mEventData->mDecoratorUpdated = true;
1810   }
1811 }
1812
1813 void Controller::Impl::ShowClipboard()
1814 {
1815   if( mClipboard )
1816   {
1817     mClipboard.ShowClipboard();
1818   }
1819 }
1820
1821 void Controller::Impl::HideClipboard()
1822 {
1823   if( mClipboard && mClipboardHideEnabled )
1824   {
1825     mClipboard.HideClipboard();
1826   }
1827 }
1828
1829 void Controller::Impl::SetClipboardHideEnable(bool enable)
1830 {
1831   mClipboardHideEnabled = enable;
1832 }
1833
1834 bool Controller::Impl::CopyStringToClipboard( std::string& source )
1835 {
1836   //Send string to clipboard
1837   return ( mClipboard && mClipboard.SetItem( source ) );
1838 }
1839
1840 void Controller::Impl::SendSelectionToClipboard( bool deleteAfterSending )
1841 {
1842   std::string selectedText;
1843   RetrieveSelection( selectedText, deleteAfterSending );
1844   CopyStringToClipboard( selectedText );
1845   ChangeState( EventData::EDITING );
1846 }
1847
1848 void Controller::Impl::RequestGetTextFromClipboard()
1849 {
1850   if ( mClipboard )
1851   {
1852     mClipboard.RequestItem();
1853   }
1854 }
1855
1856 void Controller::Impl::RepositionSelectionHandles()
1857 {
1858   CharacterIndex selectionStart = mEventData->mLeftSelectionPosition;
1859   CharacterIndex selectionEnd = mEventData->mRightSelectionPosition;
1860
1861   if( selectionStart == selectionEnd )
1862   {
1863     // Nothing to select if handles are in the same place.
1864     return;
1865   }
1866
1867   mEventData->mDecorator->ClearHighlights();
1868
1869   const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
1870   const Length* const glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
1871   const GlyphInfo* const glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
1872   const Vector2* const positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
1873   const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
1874   const CharacterIndex* const glyphToCharacterBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
1875   const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mModel->mLogicalModel->mCharacterDirections.Count() ) ? mModel->mLogicalModel->mCharacterDirections.Begin() : NULL;
1876
1877   const bool isLastCharacter = selectionEnd >= mModel->mLogicalModel->mText.Count();
1878   const CharacterDirection startDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + selectionStart ) );
1879   const CharacterDirection endDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + ( selectionEnd - ( isLastCharacter ? 1u : 0u ) ) ) );
1880
1881   // Swap the indices if the start is greater than the end.
1882   const bool indicesSwapped = selectionStart > selectionEnd;
1883
1884   // Tell the decorator to flip the selection handles if needed.
1885   mEventData->mDecorator->SetSelectionHandleFlipState( indicesSwapped, startDirection, endDirection );
1886
1887   if( indicesSwapped )
1888   {
1889     std::swap( selectionStart, selectionEnd );
1890   }
1891
1892   // Get the indices to the first and last selected glyphs.
1893   const CharacterIndex selectionEndMinusOne = selectionEnd - 1u;
1894   const GlyphIndex glyphStart = *( charactersToGlyphBuffer + selectionStart );
1895   const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + selectionEndMinusOne );
1896   const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + selectionEndMinusOne ) + ( ( numberOfGlyphs > 0 ) ? numberOfGlyphs - 1u : 0u );
1897
1898   // Get the lines where the glyphs are laid-out.
1899   const LineRun* lineRun = mModel->mVisualModel->mLines.Begin();
1900
1901   LineIndex lineIndex = 0u;
1902   Length numberOfLines = 0u;
1903   mModel->mVisualModel->GetNumberOfLines( glyphStart,
1904                                           1u + glyphEnd - glyphStart,
1905                                           lineIndex,
1906                                           numberOfLines );
1907   const LineIndex firstLineIndex = lineIndex;
1908
1909   // Create the structure to store some selection box info.
1910   Vector<SelectionBoxInfo> selectionBoxLinesInfo;
1911   selectionBoxLinesInfo.Resize( numberOfLines );
1912
1913   SelectionBoxInfo* selectionBoxInfo = selectionBoxLinesInfo.Begin();
1914   selectionBoxInfo->minX = MAX_FLOAT;
1915   selectionBoxInfo->maxX = MIN_FLOAT;
1916
1917   // Keep the min and max 'x' position to calculate the size and position of the highlighed text.
1918   float minHighlightX = std::numeric_limits<float>::max();
1919   float maxHighlightX = std::numeric_limits<float>::min();
1920   Size highLightSize;
1921   Vector2 highLightPosition; // The highlight position in decorator's coords.
1922
1923   // Retrieve the first line and get the line's vertical offset, the line's height and the index to the last glyph.
1924
1925   // The line's vertical offset of all the lines before the line where the first glyph is laid-out.
1926   selectionBoxInfo->lineOffset = CalculateLineOffset( mModel->mVisualModel->mLines,
1927                                                       firstLineIndex );
1928
1929   // Transform to decorator's (control) coords.
1930   selectionBoxInfo->lineOffset += mModel->mScrollPosition.y;
1931
1932   lineRun += firstLineIndex;
1933
1934   // The line height is the addition of the line ascender and the line descender.
1935   // However, the line descender has a negative value, hence the subtraction.
1936   selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
1937
1938   GlyphIndex lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
1939
1940   // Check if the first glyph is a ligature that must be broken like Latin ff, fi, or Arabic ï»», etc which needs special code.
1941   const Length numberOfCharactersStart = *( charactersPerGlyphBuffer + glyphStart );
1942   bool splitStartGlyph = ( numberOfCharactersStart > 1u ) && HasLigatureMustBreak( mModel->mLogicalModel->GetScript( selectionStart ) );
1943
1944   // Check if the last glyph is a ligature that must be broken like Latin ff, fi, or Arabic ï»», etc which needs special code.
1945   const Length numberOfCharactersEnd = *( charactersPerGlyphBuffer + glyphEnd );
1946   bool splitEndGlyph = ( glyphStart != glyphEnd ) && ( numberOfCharactersEnd > 1u ) && HasLigatureMustBreak( mModel->mLogicalModel->GetScript( selectionEndMinusOne ) );
1947
1948   // The number of quads of the selection box.
1949   const unsigned int numberOfQuads = 1u + ( glyphEnd - glyphStart ) + ( ( numberOfLines > 1u ) ? 2u * numberOfLines : 0u );
1950   mEventData->mDecorator->ResizeHighlightQuads( numberOfQuads );
1951
1952   // Count the actual number of quads.
1953   unsigned int actualNumberOfQuads = 0u;
1954   Vector4 quad;
1955
1956   // Traverse the glyphs.
1957   for( GlyphIndex index = glyphStart; index <= glyphEnd; ++index )
1958   {
1959     const GlyphInfo& glyph = *( glyphsBuffer + index );
1960     const Vector2& position = *( positionsBuffer + index );
1961
1962     if( splitStartGlyph )
1963     {
1964       // 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.
1965
1966       const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersStart );
1967       const CharacterIndex interGlyphIndex = selectionStart - *( glyphToCharacterBuffer + glyphStart );
1968       // Get the direction of the character.
1969       CharacterDirection isCurrentRightToLeft = false;
1970       if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
1971       {
1972         isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionStart );
1973       }
1974
1975       // The end point could be in the middle of the ligature.
1976       // Calculate the number of characters selected.
1977       const Length numberOfCharacters = ( glyphStart == glyphEnd ) ? ( selectionEnd - selectionStart ) : ( numberOfCharactersStart - interGlyphIndex );
1978
1979       quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x + glyphAdvance * static_cast<float>( isCurrentRightToLeft ? ( numberOfCharactersStart - interGlyphIndex - numberOfCharacters ) : interGlyphIndex );
1980       quad.y = selectionBoxInfo->lineOffset;
1981       quad.z = quad.x + static_cast<float>( numberOfCharacters ) * glyphAdvance;
1982       quad.w = selectionBoxInfo->lineOffset + selectionBoxInfo->lineHeight;
1983
1984       // Store the min and max 'x' for each line.
1985       selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
1986       selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
1987
1988       mEventData->mDecorator->AddHighlight( actualNumberOfQuads, quad );
1989       ++actualNumberOfQuads;
1990
1991       splitStartGlyph = false;
1992       continue;
1993     }
1994
1995     if( splitEndGlyph && ( index == glyphEnd ) )
1996     {
1997       // 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.
1998
1999       const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersEnd );
2000       const CharacterIndex interGlyphIndex = selectionEnd - *( glyphToCharacterBuffer + glyphEnd );
2001       // Get the direction of the character.
2002       CharacterDirection isCurrentRightToLeft = false;
2003       if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
2004       {
2005         isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionEnd );
2006       }
2007
2008       const Length numberOfCharacters = numberOfCharactersEnd - interGlyphIndex;
2009
2010       quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x + ( isCurrentRightToLeft ? ( glyphAdvance * static_cast<float>( numberOfCharacters ) ) : 0.f );
2011       quad.y = selectionBoxInfo->lineOffset;
2012       quad.z = quad.x + static_cast<float>( interGlyphIndex ) * glyphAdvance;
2013       quad.w = quad.y + selectionBoxInfo->lineHeight;
2014
2015       // Store the min and max 'x' for each line.
2016       selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
2017       selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
2018
2019       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2020                                             quad );
2021       ++actualNumberOfQuads;
2022
2023       splitEndGlyph = false;
2024       continue;
2025     }
2026
2027     quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x;
2028     quad.y = selectionBoxInfo->lineOffset;
2029     quad.z = quad.x + glyph.advance;
2030     quad.w = quad.y + selectionBoxInfo->lineHeight;
2031
2032     // Store the min and max 'x' for each line.
2033     selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
2034     selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
2035
2036     mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2037                                           quad );
2038     ++actualNumberOfQuads;
2039
2040     // Whether to retrieve the next line.
2041     if( index == lastGlyphOfLine )
2042     {
2043       ++lineIndex;
2044       if( lineIndex < firstLineIndex + numberOfLines )
2045       {
2046         // Retrieve the next line.
2047         ++lineRun;
2048
2049         // Get the last glyph of the new line.
2050         lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
2051
2052         // Keep the offset and height of the current selection box.
2053         const float currentLineOffset = selectionBoxInfo->lineOffset;
2054         const float currentLineHeight = selectionBoxInfo->lineHeight;
2055
2056         // Get the selection box info for the next line.
2057         ++selectionBoxInfo;
2058
2059         selectionBoxInfo->minX = MAX_FLOAT;
2060         selectionBoxInfo->maxX = MIN_FLOAT;
2061
2062         // Update the line's vertical offset.
2063         selectionBoxInfo->lineOffset = currentLineOffset + currentLineHeight;
2064
2065         // The line height is the addition of the line ascender and the line descender.
2066         // However, the line descender has a negative value, hence the subtraction.
2067         selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
2068       }
2069     }
2070   }
2071
2072   // Traverses all the lines and updates the min and max 'x' positions and the total height.
2073   // The final width is calculated after 'boxifying' the selection.
2074   for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin(),
2075          endIt = selectionBoxLinesInfo.End();
2076        it != endIt;
2077        ++it )
2078   {
2079     const SelectionBoxInfo& info = *it;
2080
2081     // Update the size of the highlighted text.
2082     highLightSize.height += info.lineHeight;
2083     minHighlightX = std::min( minHighlightX, info.minX );
2084     maxHighlightX = std::max( maxHighlightX, info.maxX );
2085   }
2086
2087   // Add extra geometry to 'boxify' the selection.
2088
2089   if( 1u < numberOfLines )
2090   {
2091     // Boxify the first line.
2092     lineRun = mModel->mVisualModel->mLines.Begin() + firstLineIndex;
2093     const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
2094
2095     bool boxifyBegin = ( LTR != lineRun->direction ) && ( LTR != startDirection );
2096     bool boxifyEnd = ( LTR == lineRun->direction ) && ( LTR == startDirection );
2097
2098     if( boxifyBegin )
2099     {
2100       quad.x = 0.f;
2101       quad.y = firstSelectionBoxLineInfo.lineOffset;
2102       quad.z = firstSelectionBoxLineInfo.minX;
2103       quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
2104
2105       // Boxify at the beginning of the line.
2106       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2107                                             quad );
2108       ++actualNumberOfQuads;
2109
2110       // Update the size of the highlighted text.
2111       minHighlightX = 0.f;
2112     }
2113
2114     if( boxifyEnd )
2115     {
2116       quad.x = firstSelectionBoxLineInfo.maxX;
2117       quad.y = firstSelectionBoxLineInfo.lineOffset;
2118       quad.z = mModel->mVisualModel->mControlSize.width;
2119       quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
2120
2121       // Boxify at the end of the line.
2122       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2123                                             quad );
2124       ++actualNumberOfQuads;
2125
2126       // Update the size of the highlighted text.
2127       maxHighlightX = mModel->mVisualModel->mControlSize.width;
2128     }
2129
2130     // Boxify the central lines.
2131     if( 2u < numberOfLines )
2132     {
2133       for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin() + 1u,
2134              endIt = selectionBoxLinesInfo.End() - 1u;
2135            it != endIt;
2136            ++it )
2137       {
2138         const SelectionBoxInfo& info = *it;
2139
2140         quad.x = 0.f;
2141         quad.y = info.lineOffset;
2142         quad.z = info.minX;
2143         quad.w = info.lineOffset + info.lineHeight;
2144
2145         mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2146                                               quad );
2147         ++actualNumberOfQuads;
2148
2149         quad.x = info.maxX;
2150         quad.y = info.lineOffset;
2151         quad.z = mModel->mVisualModel->mControlSize.width;
2152         quad.w = info.lineOffset + info.lineHeight;
2153
2154         mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2155                                               quad );
2156         ++actualNumberOfQuads;
2157       }
2158
2159       // Update the size of the highlighted text.
2160       minHighlightX = 0.f;
2161       maxHighlightX = mModel->mVisualModel->mControlSize.width;
2162     }
2163
2164     // Boxify the last line.
2165     lineRun = mModel->mVisualModel->mLines.Begin() + firstLineIndex + numberOfLines - 1u;
2166     const SelectionBoxInfo& lastSelectionBoxLineInfo = *( selectionBoxLinesInfo.End() - 1u );
2167
2168     boxifyBegin = ( LTR == lineRun->direction ) && ( LTR == endDirection );
2169     boxifyEnd = ( LTR != lineRun->direction ) && ( LTR != endDirection );
2170
2171     if( boxifyBegin )
2172     {
2173       quad.x = 0.f;
2174       quad.y = lastSelectionBoxLineInfo.lineOffset;
2175       quad.z = lastSelectionBoxLineInfo.minX;
2176       quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
2177
2178       // Boxify at the beginning of the line.
2179       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2180                                             quad );
2181       ++actualNumberOfQuads;
2182
2183       // Update the size of the highlighted text.
2184       minHighlightX = 0.f;
2185     }
2186
2187     if( boxifyEnd )
2188     {
2189       quad.x = lastSelectionBoxLineInfo.maxX;
2190       quad.y = lastSelectionBoxLineInfo.lineOffset;
2191       quad.z = mModel->mVisualModel->mControlSize.width;
2192       quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
2193
2194       // Boxify at the end of the line.
2195       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2196                                             quad );
2197       ++actualNumberOfQuads;
2198
2199       // Update the size of the highlighted text.
2200       maxHighlightX = mModel->mVisualModel->mControlSize.width;
2201     }
2202   }
2203
2204   // Set the actual number of quads.
2205   mEventData->mDecorator->ResizeHighlightQuads( actualNumberOfQuads );
2206
2207   // Sets the highlight's size and position. In decorator's coords.
2208   // The highlight's height has been calculated above (before 'boxifying' the highlight).
2209   highLightSize.width = maxHighlightX - minHighlightX;
2210
2211   highLightPosition.x = minHighlightX;
2212   const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
2213   highLightPosition.y = firstSelectionBoxLineInfo.lineOffset;
2214
2215   mEventData->mDecorator->SetHighLightBox( highLightPosition, highLightSize );
2216
2217   if( !mEventData->mDecorator->IsSmoothHandlePanEnabled() )
2218   {
2219     CursorInfo primaryCursorInfo;
2220     GetCursorPosition( mEventData->mLeftSelectionPosition,
2221                        primaryCursorInfo );
2222
2223     const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + mModel->mScrollPosition;
2224
2225     mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE,
2226                                          primaryPosition.x,
2227                                          primaryCursorInfo.lineOffset + mModel->mScrollPosition.y,
2228                                          primaryCursorInfo.lineHeight );
2229
2230     CursorInfo secondaryCursorInfo;
2231     GetCursorPosition( mEventData->mRightSelectionPosition,
2232                        secondaryCursorInfo );
2233
2234     const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + mModel->mScrollPosition;
2235
2236     mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE,
2237                                          secondaryPosition.x,
2238                                          secondaryCursorInfo.lineOffset + mModel->mScrollPosition.y,
2239                                          secondaryCursorInfo.lineHeight );
2240   }
2241
2242   // Cursor to be positioned at end of selection so if selection interrupted and edit mode restarted the cursor will be at end of selection
2243   mEventData->mPrimaryCursorPosition = ( indicesSwapped ) ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
2244
2245   // Set the flag to update the decorator.
2246   mEventData->mDecoratorUpdated = true;
2247 }
2248
2249 void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY, Controller::NoTextTap::Action action )
2250 {
2251   if( NULL == mEventData )
2252   {
2253     // Nothing to do if there is no text input.
2254     return;
2255   }
2256
2257   if( IsShowingPlaceholderText() )
2258   {
2259     // Nothing to do if there is the place-holder text.
2260     return;
2261   }
2262
2263   const Length numberOfGlyphs = mModel->mVisualModel->mGlyphs.Count();
2264   const Length numberOfLines  = mModel->mVisualModel->mLines.Count();
2265   if( ( 0 == numberOfGlyphs ) ||
2266       ( 0 == numberOfLines ) )
2267   {
2268     // Nothing to do if there is no text.
2269     return;
2270   }
2271
2272   // Find which word was selected
2273   CharacterIndex selectionStart( 0 );
2274   CharacterIndex selectionEnd( 0 );
2275   CharacterIndex noTextHitIndex( 0 );
2276   const bool characterHit = FindSelectionIndices( mModel->mVisualModel,
2277                                                   mModel->mLogicalModel,
2278                                                   mMetrics,
2279                                                   visualX,
2280                                                   visualY,
2281                                                   selectionStart,
2282                                                   selectionEnd,
2283                                                   noTextHitIndex );
2284   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
2285
2286   if( characterHit || ( Controller::NoTextTap::HIGHLIGHT == action ) )
2287   {
2288     ChangeState( EventData::SELECTING );
2289
2290     mEventData->mLeftSelectionPosition = selectionStart;
2291     mEventData->mRightSelectionPosition = selectionEnd;
2292
2293     mEventData->mUpdateLeftSelectionPosition = true;
2294     mEventData->mUpdateRightSelectionPosition = true;
2295     mEventData->mUpdateHighlightBox = true;
2296
2297     // It may happen an IMF commit event arrives before the selection event
2298     // if the IMF manager is in pre-edit state. The commit event will set the
2299     // mEventData->mUpdateCursorPosition flag to true. If it's not set back
2300     // to false, the highlight box won't be updated.
2301     mEventData->mUpdateCursorPosition = false;
2302
2303     mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
2304   }
2305   else if( Controller::NoTextTap::SHOW_SELECTION_POPUP == action )
2306   {
2307     // Nothing to select. i.e. a white space, out of bounds
2308     ChangeState( EventData::EDITING_WITH_POPUP );
2309
2310     mEventData->mPrimaryCursorPosition = noTextHitIndex;
2311
2312     mEventData->mUpdateCursorPosition = true;
2313     mEventData->mUpdateGrabHandlePosition = true;
2314     mEventData->mScrollAfterUpdatePosition = true;
2315     mEventData->mUpdateInputStyle = true;
2316   }
2317   else if( Controller::NoTextTap::NO_ACTION == action )
2318   {
2319     // Nothing to select. i.e. a white space, out of bounds
2320     mEventData->mPrimaryCursorPosition = noTextHitIndex;
2321
2322     mEventData->mUpdateCursorPosition = true;
2323     mEventData->mUpdateGrabHandlePosition = true;
2324     mEventData->mScrollAfterUpdatePosition = true;
2325     mEventData->mUpdateInputStyle = true;
2326   }
2327 }
2328
2329 void Controller::Impl::SetPopupButtons()
2330 {
2331   /**
2332    *  Sets the Popup buttons to be shown depending on State.
2333    *
2334    *  If SELECTING :  CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
2335    *
2336    *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
2337    */
2338
2339   TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
2340
2341   if( EventData::SELECTING == mEventData->mState )
2342   {
2343     buttonsToShow = TextSelectionPopup::Buttons(  TextSelectionPopup::CUT | TextSelectionPopup::COPY );
2344
2345     if( !IsClipboardEmpty() )
2346     {
2347       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2348       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2349     }
2350
2351     if( !mEventData->mAllTextSelected )
2352     {
2353       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::SELECT_ALL ) );
2354     }
2355   }
2356   else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
2357   {
2358     if( mModel->mLogicalModel->mText.Count() && !IsShowingPlaceholderText() )
2359     {
2360       buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL );
2361     }
2362
2363     if( !IsClipboardEmpty() )
2364     {
2365       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2366       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2367     }
2368   }
2369   else if( EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState )
2370   {
2371     if ( !IsClipboardEmpty() )
2372     {
2373       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2374       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2375     }
2376   }
2377
2378   mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
2379 }
2380
2381 void Controller::Impl::ChangeState( EventData::State newState )
2382 {
2383   if( NULL == mEventData )
2384   {
2385     // Nothing to do if there is no text input.
2386     return;
2387   }
2388
2389   DALI_LOG_INFO( gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState );
2390
2391   if( mEventData->mState != newState )
2392   {
2393     mEventData->mPreviousState = mEventData->mState;
2394     mEventData->mState = newState;
2395
2396     switch( mEventData->mState )
2397     {
2398       case EventData::INACTIVE:
2399       {
2400         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2401         mEventData->mDecorator->StopCursorBlink();
2402         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2403         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2404         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2405         mEventData->mDecorator->SetHighlightActive( false );
2406         mEventData->mDecorator->SetPopupActive( false );
2407         mEventData->mDecoratorUpdated = true;
2408         break;
2409       }
2410       case EventData::INTERRUPTED:
2411       {
2412         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2413         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2414         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2415         mEventData->mDecorator->SetHighlightActive( false );
2416         mEventData->mDecorator->SetPopupActive( false );
2417         mEventData->mDecoratorUpdated = true;
2418         break;
2419       }
2420       case EventData::SELECTING:
2421       {
2422         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2423         mEventData->mDecorator->StopCursorBlink();
2424         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2425         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
2426         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
2427         mEventData->mDecorator->SetHighlightActive( true );
2428         if( mEventData->mGrabHandlePopupEnabled )
2429         {
2430           SetPopupButtons();
2431           mEventData->mDecorator->SetPopupActive( true );
2432         }
2433         mEventData->mDecoratorUpdated = true;
2434         break;
2435       }
2436       case EventData::EDITING:
2437       {
2438         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2439         if( mEventData->mCursorBlinkEnabled )
2440         {
2441           mEventData->mDecorator->StartCursorBlink();
2442         }
2443         // Grab handle is not shown until a tap is received whilst EDITING
2444         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2445         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2446         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2447         mEventData->mDecorator->SetHighlightActive( false );
2448         if( mEventData->mGrabHandlePopupEnabled )
2449         {
2450           mEventData->mDecorator->SetPopupActive( false );
2451         }
2452         mEventData->mDecoratorUpdated = true;
2453         break;
2454       }
2455       case EventData::EDITING_WITH_POPUP:
2456       {
2457         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState );
2458
2459         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2460         if( mEventData->mCursorBlinkEnabled )
2461         {
2462           mEventData->mDecorator->StartCursorBlink();
2463         }
2464         if( mEventData->mSelectionEnabled )
2465         {
2466           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2467           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2468           mEventData->mDecorator->SetHighlightActive( false );
2469         }
2470         else
2471         {
2472           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2473         }
2474         if( mEventData->mGrabHandlePopupEnabled )
2475         {
2476           SetPopupButtons();
2477           mEventData->mDecorator->SetPopupActive( true );
2478         }
2479         mEventData->mDecoratorUpdated = true;
2480         break;
2481       }
2482       case EventData::EDITING_WITH_GRAB_HANDLE:
2483       {
2484         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState );
2485
2486         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2487         if( mEventData->mCursorBlinkEnabled )
2488         {
2489           mEventData->mDecorator->StartCursorBlink();
2490         }
2491         // Grab handle is not shown until a tap is received whilst EDITING
2492         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2493         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2494         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2495         mEventData->mDecorator->SetHighlightActive( false );
2496         if( mEventData->mGrabHandlePopupEnabled )
2497         {
2498           mEventData->mDecorator->SetPopupActive( false );
2499         }
2500         mEventData->mDecoratorUpdated = true;
2501         break;
2502       }
2503       case EventData::SELECTION_HANDLE_PANNING:
2504       {
2505         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2506         mEventData->mDecorator->StopCursorBlink();
2507         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2508         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
2509         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
2510         mEventData->mDecorator->SetHighlightActive( true );
2511         if( mEventData->mGrabHandlePopupEnabled )
2512         {
2513           mEventData->mDecorator->SetPopupActive( false );
2514         }
2515         mEventData->mDecoratorUpdated = true;
2516         break;
2517       }
2518       case EventData::GRAB_HANDLE_PANNING:
2519       {
2520         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState );
2521
2522         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2523         if( mEventData->mCursorBlinkEnabled )
2524         {
2525           mEventData->mDecorator->StartCursorBlink();
2526         }
2527         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2528         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2529         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2530         mEventData->mDecorator->SetHighlightActive( false );
2531         if( mEventData->mGrabHandlePopupEnabled )
2532         {
2533           mEventData->mDecorator->SetPopupActive( false );
2534         }
2535         mEventData->mDecoratorUpdated = true;
2536         break;
2537       }
2538       case EventData::EDITING_WITH_PASTE_POPUP:
2539       {
2540         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState );
2541
2542         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2543         if( mEventData->mCursorBlinkEnabled )
2544         {
2545           mEventData->mDecorator->StartCursorBlink();
2546         }
2547
2548         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2549         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2550         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2551         mEventData->mDecorator->SetHighlightActive( false );
2552
2553         if( mEventData->mGrabHandlePopupEnabled )
2554         {
2555           SetPopupButtons();
2556           mEventData->mDecorator->SetPopupActive( true );
2557         }
2558         mEventData->mDecoratorUpdated = true;
2559         break;
2560       }
2561       case EventData::TEXT_PANNING:
2562       {
2563         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2564         mEventData->mDecorator->StopCursorBlink();
2565         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2566         if( mEventData->mDecorator->IsHandleActive( LEFT_SELECTION_HANDLE ) ||
2567             mEventData->mDecorator->IsHandleActive( RIGHT_SELECTION_HANDLE ) )
2568         {
2569           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2570           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2571           mEventData->mDecorator->SetHighlightActive( true );
2572         }
2573
2574         if( mEventData->mGrabHandlePopupEnabled )
2575         {
2576           mEventData->mDecorator->SetPopupActive( false );
2577         }
2578
2579         mEventData->mDecoratorUpdated = true;
2580         break;
2581       }
2582     }
2583   }
2584 }
2585
2586 void Controller::Impl::GetCursorPosition( CharacterIndex logical,
2587                                           CursorInfo& cursorInfo )
2588 {
2589   if( !IsShowingRealText() )
2590   {
2591     // Do not want to use the place-holder text to set the cursor position.
2592
2593     // Use the line's height of the font's family set to set the cursor's size.
2594     // If there is no font's family set, use the default font.
2595     // Use the current alignment to place the cursor at the beginning, center or end of the box.
2596
2597     cursorInfo.lineOffset = 0.f;
2598     cursorInfo.lineHeight = GetDefaultFontLineHeight();
2599     cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
2600
2601     switch( mModel->mHorizontalAlignment )
2602     {
2603       case Layout::HORIZONTAL_ALIGN_BEGIN:
2604       {
2605         cursorInfo.primaryPosition.x = 0.f;
2606         break;
2607       }
2608       case Layout::HORIZONTAL_ALIGN_CENTER:
2609       {
2610         cursorInfo.primaryPosition.x = floorf( 0.5f * mModel->mVisualModel->mControlSize.width );
2611         break;
2612       }
2613       case Layout::HORIZONTAL_ALIGN_END:
2614       {
2615         cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
2616         break;
2617       }
2618     }
2619
2620     // Nothing else to do.
2621     return;
2622   }
2623
2624   Text::GetCursorPosition( mModel->mVisualModel,
2625                            mModel->mLogicalModel,
2626                            mMetrics,
2627                            logical,
2628                            cursorInfo );
2629
2630   if( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() )
2631   {
2632     // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
2633
2634     // Note the white spaces laid-out at the end of the line might exceed the boundaries of the control.
2635     // The reason is a wrapped line must not start with a white space so they are laid-out at the end of the line.
2636
2637     if( 0.f > cursorInfo.primaryPosition.x )
2638     {
2639       cursorInfo.primaryPosition.x = 0.f;
2640     }
2641
2642     const float edgeWidth = mModel->mVisualModel->mControlSize.width - static_cast<float>( mEventData->mDecorator->GetCursorWidth() );
2643     if( cursorInfo.primaryPosition.x > edgeWidth )
2644     {
2645       cursorInfo.primaryPosition.x = edgeWidth;
2646     }
2647   }
2648 }
2649
2650 CharacterIndex Controller::Impl::CalculateNewCursorIndex( CharacterIndex index ) const
2651 {
2652   if( NULL == mEventData )
2653   {
2654     // Nothing to do if there is no text input.
2655     return 0u;
2656   }
2657
2658   CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
2659
2660   const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
2661   const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
2662
2663   GlyphIndex glyphIndex = *( charactersToGlyphBuffer + index );
2664   Length numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
2665
2666   if( numberOfCharacters > 1u )
2667   {
2668     const Script script = mModel->mLogicalModel->GetScript( index );
2669     if( HasLigatureMustBreak( script ) )
2670     {
2671       // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ï»», ...
2672       numberOfCharacters = 1u;
2673     }
2674   }
2675   else
2676   {
2677     while( 0u == numberOfCharacters )
2678     {
2679       ++glyphIndex;
2680       numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
2681     }
2682   }
2683
2684   if( index < mEventData->mPrimaryCursorPosition )
2685   {
2686     cursorIndex -= numberOfCharacters;
2687   }
2688   else
2689   {
2690     cursorIndex += numberOfCharacters;
2691   }
2692
2693   // Will update the cursor hook position.
2694   mEventData->mUpdateCursorHookPosition = true;
2695
2696   return cursorIndex;
2697 }
2698
2699 void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo )
2700 {
2701   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this );
2702   if( NULL == mEventData )
2703   {
2704     // Nothing to do if there is no text input.
2705     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n" );
2706     return;
2707   }
2708
2709   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
2710
2711   mEventData->mDecorator->SetGlyphOffset( PRIMARY_CURSOR, cursorInfo.glyphOffset );
2712
2713   // Sets the cursor position.
2714   mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
2715                                        cursorPosition.x,
2716                                        cursorPosition.y,
2717                                        cursorInfo.primaryCursorHeight,
2718                                        cursorInfo.lineHeight );
2719   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y );
2720
2721   if( mEventData->mUpdateGrabHandlePosition )
2722   {
2723     // Sets the grab handle position.
2724     mEventData->mDecorator->SetPosition( GRAB_HANDLE,
2725                                          cursorPosition.x,
2726                                          cursorInfo.lineOffset + mModel->mScrollPosition.y,
2727                                          cursorInfo.lineHeight );
2728   }
2729
2730   if( cursorInfo.isSecondaryCursor )
2731   {
2732     mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
2733                                          cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x,
2734                                          cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y,
2735                                          cursorInfo.secondaryCursorHeight,
2736                                          cursorInfo.lineHeight );
2737     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x, cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y );
2738   }
2739
2740   // Set which cursors are active according the state.
2741   if( EventData::IsEditingState( mEventData->mState ) || ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) )
2742   {
2743     if( cursorInfo.isSecondaryCursor )
2744     {
2745       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
2746     }
2747     else
2748     {
2749       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2750     }
2751   }
2752   else
2753   {
2754     mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2755   }
2756
2757   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n" );
2758 }
2759
2760 void Controller::Impl::UpdateSelectionHandle( HandleType handleType,
2761                                               const CursorInfo& cursorInfo )
2762 {
2763   if( ( LEFT_SELECTION_HANDLE != handleType ) &&
2764       ( RIGHT_SELECTION_HANDLE != handleType ) )
2765   {
2766     return;
2767   }
2768
2769   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
2770
2771   // Sets the handle's position.
2772   mEventData->mDecorator->SetPosition( handleType,
2773                                        cursorPosition.x,
2774                                        cursorInfo.lineOffset + mModel->mScrollPosition.y,
2775                                        cursorInfo.lineHeight );
2776
2777   // If selection handle at start of the text and other at end of the text then all text is selected.
2778   const CharacterIndex startOfSelection = std::min( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
2779   const CharacterIndex endOfSelection = std::max ( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
2780   mEventData->mAllTextSelected = ( startOfSelection == 0 ) && ( endOfSelection == mModel->mLogicalModel->mText.Count() );
2781 }
2782
2783 void Controller::Impl::ClampHorizontalScroll( const Vector2& layoutSize )
2784 {
2785   // Clamp between -space & -alignment offset.
2786
2787   if( layoutSize.width > mModel->mVisualModel->mControlSize.width )
2788   {
2789     const float space = ( layoutSize.width - mModel->mVisualModel->mControlSize.width ) + mModel->mAlignmentOffset;
2790     mModel->mScrollPosition.x = ( mModel->mScrollPosition.x < -space ) ? -space : mModel->mScrollPosition.x;
2791     mModel->mScrollPosition.x = ( mModel->mScrollPosition.x > -mModel->mAlignmentOffset ) ? -mModel->mAlignmentOffset : mModel->mScrollPosition.x;
2792
2793     mEventData->mDecoratorUpdated = true;
2794   }
2795   else
2796   {
2797     mModel->mScrollPosition.x = 0.f;
2798   }
2799 }
2800
2801 void Controller::Impl::ClampVerticalScroll( const Vector2& layoutSize )
2802 {
2803   if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
2804   {
2805     // Nothing to do if the text is single line.
2806     return;
2807   }
2808
2809   // Clamp between -space & 0.
2810   if( layoutSize.height > mModel->mVisualModel->mControlSize.height )
2811   {
2812     const float space = ( layoutSize.height - mModel->mVisualModel->mControlSize.height );
2813     mModel->mScrollPosition.y = ( mModel->mScrollPosition.y < -space ) ? -space : mModel->mScrollPosition.y;
2814     mModel->mScrollPosition.y = ( mModel->mScrollPosition.y > 0.f ) ? 0.f : mModel->mScrollPosition.y;
2815
2816     mEventData->mDecoratorUpdated = true;
2817   }
2818   else
2819   {
2820     mModel->mScrollPosition.y = 0.f;
2821   }
2822 }
2823
2824 void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position, float lineHeight )
2825 {
2826   const float cursorWidth = mEventData->mDecorator ? static_cast<float>( mEventData->mDecorator->GetCursorWidth() ) : 0.f;
2827
2828   // position is in actor's coords.
2829   const float positionEndX = position.x + cursorWidth;
2830   const float positionEndY = position.y + lineHeight;
2831
2832   // Transform the position to decorator coords.
2833   const float decoratorPositionBeginX = position.x + mModel->mScrollPosition.x;
2834   const float decoratorPositionEndX = positionEndX + mModel->mScrollPosition.x;
2835
2836   const float decoratorPositionBeginY = position.y + mModel->mScrollPosition.y;
2837   const float decoratorPositionEndY = positionEndY + mModel->mScrollPosition.y;
2838
2839   if( decoratorPositionBeginX < 0.f )
2840   {
2841     mModel->mScrollPosition.x = -position.x;
2842   }
2843   else if( decoratorPositionEndX > mModel->mVisualModel->mControlSize.width )
2844   {
2845     mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
2846   }
2847
2848   if( decoratorPositionBeginY < 0.f )
2849   {
2850     mModel->mScrollPosition.y = -position.y;
2851   }
2852   else if( decoratorPositionEndY > mModel->mVisualModel->mControlSize.height )
2853   {
2854     mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
2855   }
2856 }
2857
2858 void Controller::Impl::ScrollTextToMatchCursor( const CursorInfo& cursorInfo )
2859 {
2860   // Get the current cursor position in decorator coords.
2861   const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2862
2863   const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( mEventData->mPrimaryCursorPosition  );
2864
2865
2866
2867   // Calculate the offset to match the cursor position before the character was deleted.
2868   mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
2869
2870   //If text control has more than two lines and current line index is not last, calculate scrollpositionY
2871   if( mModel->mVisualModel->mLines.Count() > 1u && lineIndex != mModel->mVisualModel->mLines.Count() -1u )
2872   {
2873     const float currentCursorGlyphOffset = mEventData->mDecorator->GetGlyphOffset( PRIMARY_CURSOR );
2874     mModel->mScrollPosition.y = currentCursorPosition.y - cursorInfo.lineOffset - currentCursorGlyphOffset;
2875   }
2876
2877
2878   ClampHorizontalScroll( mModel->mVisualModel->GetLayoutSize() );
2879   ClampVerticalScroll( mModel->mVisualModel->GetLayoutSize() );
2880
2881   // Makes the new cursor position visible if needed.
2882   ScrollToMakePositionVisible( cursorInfo.primaryPosition, cursorInfo.lineHeight );
2883 }
2884
2885 void Controller::Impl::RequestRelayout()
2886 {
2887   if( NULL != mControlInterface )
2888   {
2889     mControlInterface->RequestTextRelayout();
2890   }
2891 }
2892
2893 } // namespace Text
2894
2895 } // namespace Toolkit
2896
2897 } // namespace Dali