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