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