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