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