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